SpringSecurity配合Thymeleaf实现详解,以及实战用例
目录
Spring Security介绍
Spring Security的核心功能:
配合Thymeleaf的Spring Security用法解析
1. 引入Spring Security和Thymeleaf依赖
2. 配置Spring Security
3. Thymeleaf与Spring Security标签
4. Spring Security表单认证
5. 示例:登录页面与权限控制
SpringBoot+Thymeleaf完成安全认证,登录登出操作。
Spring Security介绍
Spring Security是一个强大的认证和授权框架,用于保护基于Spring的应用程序。它提供了全面的安全功能,包括认证、授权、攻击防护等,能够有效地帮助开发者构建安全的Web应用程序。
Spring Security的核心功能:
1.认证(Authentication):
- 用于确认用户身份,常见的认证方式有用户名密码、OAuth、LDAP等。
- Spring Security支持多种身份验证机制,如基于表单的认证、HTTP基本认证等。
2.授权(Authorization):
- 用于确定用户是否有权限访问特定资源或操作。
- 可以基于角色、权限进行细粒度的控制,也可以根据访问路径、HTTP方法进行安全控制。
3.CSRF防护:
- Spring Security内置了对跨站请求伪造(CSRF)攻击的防护。
4.会话管理:
- 提供会话固定 Fixation)防护和并发会话控制。攻击(Session)
5.密码加密:
- 提供了多种密码加密方式,常用的如BCrypt、PBKDF2等。
6.自定义过滤器
- 可以在Spring Security的过滤链中插入自定义过滤器,满足业务需求。
配合Thymeleaf的Spring Security用法解析
Thymeleaf是一个流行的Java模板引擎,广泛用于Web应用程序中构建动态内容。与Spring Security结合使用时,Thymeleaf可以通过其springSecurity
命名空间来帮助处理与安全相关的元素。
1. 引入Spring Security和Thymeleaf依赖
在pom.xml
中添加以下依赖:
<dependencies><!-- Spring Security --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency><!-- Spring Thymeleaf --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency><!-- Spring Security Thymeleaf --><dependency><groupId>org.springframework.security</groupId><artifactId>spring-security-taglibs</artifactId></dependency>
</dependencies>
2. 配置Spring Security
在Spring Boot中,可以通过application.properties
或者application.yml
来配置Spring Security的基础功能。
# 禁用默认的登录页面
spring.security.form.login.enabled=false
# 自定义登录页面URL
spring.security.form.login.login-page=/login
3. Thymeleaf与Spring Security标签
在Thymeleaf模板中,可以使用Spring Security提供的标签来进行权限控制、条件判断等。
登录表单:通过<form>
和Spring Security的标签,可以创建一个登录表单。
<form th:action="@{/login}" method="post"><div><label for="username">Username:</label><input type="text" name="username" id="username" required="required"/></div><div><label for="password">Password:</label><input type="password" name="password" id="password" required="required"/></div><div><button type="submit">Login</button></div>
</form>
授权控制:使用sec:authorize
标签来控制某些元素的可见性或执行的条件。
<div sec:authorize="isAuthenticated()"><!-- 只有已认证用户才能看到的内容 --><p>Welcome, authenticated user!</p>
</div><div sec:authorize="hasRole('ADMIN')"><!-- 只有ADMIN角色用户能看到的内容 --><p>Admin dashboard</p>
</div>
退出登录:通过Thymeleaf与Spring Security集成,可以创建一个退出登录的链接。
<a sec:authorize="isAuthenticated()" href="/logout">Logout</a>
4. Spring Security表单认证
Spring Security提供了一些基本的配置来启用基于表单的认证。可以在配置类中自定义登录页面、注销页面、登录失败和成功的处理等。
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().antMatchers("/login", "/css/**", "/js/**").permitAll() // 允许所有人访问登录页面和静态资源.anyRequest().authenticated() // 其他页面需要认证.and().formLogin().loginPage("/login") // 自定义登录页面.permitAll().and().logout().permitAll();}@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {// 配置内存中的用户和角色auth.inMemoryAuthentication().withUser("user").password(passwordEncoder().encode("password")).roles("USER").and().withUser("admin").password(passwordEncoder().encode("admin")).roles("ADMIN");}@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}
}
5. 示例:登录页面与权限控制
创建一个简单的登录页面login.html
,通过Spring Security控制访问权限:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5">
<head><title>Login</title>
</head>
<body><h1>Login</h1><form action="#" th:action="@{/login}" method="post"><div><label for="username">Username:</label><input type="text" name="username" id="username" /></div><div><label for="password">Password:</label><input type="password" name="password" id="password" /></div><button type="submit">Login</button></form><div sec:authorize="isAuthenticated()"><p>You are logged in!</p></div>
</body>
</html>
SpringBoot+Thymeleaf完成安全认证,登录登出操作。
1.导入Maven坐标
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency><groupId>org.springframework.security</groupId><artifactId>spring-security-config</artifactId>
</dependency>
<dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.3.31</version>
</dependency>
2.AuthInterceptor拦截器
package com.book.interceptor;import org.springframework.web.servlet.HandlerInterceptor;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public class AuthInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request,HttpServletResponse response,Object handler) throws Exception {HttpSession session = request.getSession(false);// 排除登录、注册等公开页面String uri = request.getRequestURI();if (uri.startsWith("/user/login") || uri.startsWith("/user/register") ||uri.startsWith("/static/") || uri.equals("/")) {return true;}// 检查session中的用户信息if (session == null || session.getAttribute("user") == null) {response.sendRedirect("/user/login");return false;}return true;}
}
3.WebConfig注册拦截器
package com.book.config;
import com.book.interceptor.AuthInterceptor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration
@Slf4j
public class WebConfig implements WebMvcConfigurer {/*** 注册自定义拦截器** @param registry*/@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new AuthInterceptor()).addPathPatterns("/**").excludePathPatterns("/user/login","/user/register","/css/**","/js/**","/error");}@Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry) {// 映射本地文件系统到 "/uploads/**"registry.addResourceHandler("/uploads/**").addResourceLocations("file:///F:/SpringBoot/libraryManagement/uploads/");}
}
4.SecurityConfig安全配置
package com.book.config;import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.csrf.CookieCsrfTokenRepository;@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().antMatchers("/user/login", "/user/register", "/css/**","/js/**").permitAll().anyRequest().authenticated().and()// 完全禁用Spring Security的表单登录.formLogin().disable()// 禁用默认的/logout处理.logout().disable().csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()).and().sessionManagement().sessionFixation().migrateSession().maximumSessions(1).maxSessionsPreventsLogin(false).expiredUrl("/user/login?expired=true");}
}
5.Controller-登录登出操作
登录成功后重定向至book/list
@PostMapping("/login")
public String handleLogin(@RequestParam String username,@RequestParam String password,HttpSession session) {log.info("登录请求 - username: {}", username);User loginUser = userService.getUserByUsername(username);if (loginUser == null || !HashUtils.verifyPassword(password, loginUser.getPassword(), loginUser.getSalt())) {return "redirect:/user/login?error=true";}// 1. 设置sessionsession.setAttribute("user", loginUser);// 2. 设置Spring Security认证上下文(关键)Authentication auth = new UsernamePasswordAuthenticationToken(loginUser.getUsername(),null,Collections.singletonList(new SimpleGrantedAuthority("ROLE_USER")) // 假设所有用户都有USER角色);SecurityContextHolder.getContext().setAuthentication(auth);return "redirect:/book/list";
}//登出操作,使session事物失效
@GetMapping("/logout")
public String logout(HttpSession session) {session.invalidate();return "redirect:/user/login";
}
6.login.html用户登录页面
ps:表单一定要包含这部分
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}"/>
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head><meta charset="UTF-8"><title>用户登录</title><link rel="stylesheet" th:href="@{/css/bootstrap.min.css}"/>
</head>
<body>
<div class="container mt-5"><div class="row justify-content-center"><div class="col-md-6 col-lg-4"><div class="card shadow"><div class="card-body"><h3 class="card-title text-center mb-4">用户登录</h3><!-- 错误消息 --><div th:if="${errorMsg}" class="alert alert-danger" th:text="${errorMsg}"></div><!-- 传统表单提交到自定义Controller --><form th:action="@{/user/login}" method="post"><input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}"/><div class="mb-3"><label for="username" class="form-label">用户名</label><input type="text" class="form-control" id="username" name="username" required></div><div class="mb-3"><label for="password" class="form-label">密码</label><input type="password" class="form-control" id="password" name="password" required></div><div class="d-grid gap-2"><button type="submit" class="btn btn-primary">登录</button></div></form><div class="mt-3 text-center"><a th:href="@{/user/register}" class="text-decoration-none">还没有账号?立即注册</a></div></div></div></div></div>
</div>
</body>
</html>
总结
Spring Security和Thymeleaf结合使用,可以轻松地在Web应用中实现认证和授权功能。通过Spring Security的标签(如sec:authorize
)和Thymeleaf的模板引擎,可以在页面中实现动态的权限控制、用户认证等操作,增强了Web应用的安全性。