文章目录
一、Thymeleaf-Security
- Spring Security 可以在一些视图技术中进行控制显示效果,如JSP 或 Thymeleaf
- 在非前后端分离且使用 Spring Boot 的项目中大多使用 Thymeleaf 作为视图展示技术
- Thymeleaf 对 Spring Security 的支持都放在hymeleaf-extras-springsecurityX中,目前最新版本为 5。所以需要在项目中添加此 jar 包的依赖和 thymeleaf 的依赖
<!-- thymeleaf依赖 -->
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity5</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
- 在 html 页面中引入thymeleaf命名空间和security命名空间,引用命名空间之后才能使用对应属性信息
<!DOCTYPE html>
<html lang="zh"
xmlns:th="http://www.thymeleaf.org"
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5">
</html>
- 配置文件中配置thymeleaf相关属性,默认属性参考类
- org.springframework.boot.autoconfigure.thymeleaf.ThymeleafProperties
spring:
# Thymeleaf
thymeleaf:
# 关闭缓存
cache: false
# 开启引擎
enabled: true
# 视图模型
mode: HTML
# 指定后缀
suffix: .html
# 模板路径
prefix: classpath:/templates/
二、Thymeleaf获取属性
2.1 获取属性
- 可以在html页面中通过 sec:authentication="" 获取 UsernamePasswordAuthenticationToken 中以及父类中的属性
- org.springframework.security.authentication.UsernamePasswordAuthenticationToken
2. 源码属性如下
- name :登录账号名称
- principal:登录主体,在自定义登录逻辑中是 UserDetails
- credentials:凭证信息
- authorities:权限和角色
- details:WebAuthenticationDetails实例,可以获取 remoteAddress (客户端ip)和 sessionId (当前 sessionId)
3. 在 /templates/ 新建 security.html 用于显示上述所述属性信息
<!DOCTYPE html>
<html lang="zh"
xmlns:th="http://www.thymeleaf.org"
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5">
<head>
<meta charset="UTF-8">
<title>权限信息</title>
</head>
<body>
<ol>
<!-- 属性获取,authentication:n. 证明;鉴定;证实 -->
<li>登录账号:<span sec:authentication="name"></span></li>
<!-- principal相当于UserDetails信息 -->
<li>登录账号:<span sec:authentication="principal.username"></span></li>
<li>登录密码:<span sec:authentication="principal.password"></span></li>
<li>账号过期:<span sec:authentication="principal.accountNonExpired"></span></li>
<li>账号锁定:<span sec:authentication="principal.accountNonLocked"></span></li>
<li>凭证过期:<span sec:authentication="principal.credentialsNonExpired"></span></li>
<li>账号启用:<span sec:authentication="principal.enabled"></span></li>
<li>凭证:<span sec:authentication="credentials"></span></li>
<li>权限和角色:<span sec:authentication="authorities"></span></li>
<!-- WebAuthenticationDetails实例 -->
<li>客户端地址:<span sec:authentication="details.remoteAddress"></span></li>
<li>sessionId:<span sec:authentication="details.sessionId"></span></li>
</ol>
</body>
</html>
- 在控制器中添加转发路径,必须要通过转化,直接访问无法获取属性
@RequestMapping("/security")
public String security() {
return "security";
}
- 正常访问项目,可以显示如下权限信息
登录账号:admin
登录账号:admin
登录密码:$2a$10$.9UpYAxTDg/cd8U7wtal5et7TcC7QaInySM1p8tBEp.OO20UvjR/S
账号过期:true
账号锁定:true
凭证过期:true
账号启用:true
凭证:
权限和角色:[{"authority":"ROLE_USER","id":3,"userId":2}]
客户端地址:0:0:0:0:0:0:0:1
sessionId:CAD8A5A28BC2EBDDF0990111BC86C3CA
2.2 权限判断
- 可以在html页面中通过sec:authorize="" 进行鉴权,用来控制是否对应用户具备对应菜单
- 在security.html中增加权限相关信息
<!DOCTYPE html>
<html lang="zh"
xmlns:th="http://www.thymeleaf.org"
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5">
<head>
<meta charset="UTF-8">
<title>权限信息</title>
</head>
<body>
<ol>
<!-- 属性获取,authentication:n. 证明;鉴定;证实 -->
<li>登录账号:<span sec:authentication="name"></span></li>
<!-- principal相当于UserDetails信息 -->
<li>登录账号:<span sec:authentication="principal.username"></span></li>
<li>登录密码:<span sec:authentication="principal.password"></span></li>
<li>账号过期:<span sec:authentication="principal.accountNonExpired"></span></li>
<li>账号锁定:<span sec:authentication="principal.accountNonLocked"></span></li>
<li>凭证过期:<span sec:authentication="principal.credentialsNonExpired"></span></li>
<li>账号启用:<span sec:authentication="principal.enabled"></span></li>
<li>凭证:<span sec:authentication="credentials"></span></li>
<li>权限和角色:<span sec:authentication="authorities"></span></li>
<!-- WebAuthenticationDetails实例 -->
<li>客户端地址:<span sec:authentication="details.remoteAddress"></span></li>
<li>sessionId:<span sec:authentication="details.sessionId"></span></li>
</ol>
<div>
<!-- 权限判断,authorize:vt. 批准,认可;授权给;委托代替 -->
通过权限判断:
<button sec:authorize="hasAuthority('ROLE_ADMIN')">新增</button>
<button sec:authorize="hasAuthority('ROLE_ADMIN')">删除</button>
<button sec:authorize="hasAuthority('ROLE_ADMIN')">修改</button>
<button sec:authorize="hasAnyAuthority('ROLE_ADMIN', 'ROLE_USER')">查看</button>
<br/>
通过角色判断:
<button sec:authorize="hasRole('ADMIN')">新增</button>
<button sec:authorize="hasRole('ADMIN')">删除</button>
<button sec:authorize="hasRole('ADMIN')">修改</button>
<button sec:authorize="hasAnyRole('ADMIN', 'USER')">查看</button>
</div>
</body>
</html>
- 和 access() 中表达式使用一致,分别使用admin和root用户登录,可以看到菜单部分对于没有权限的菜单并不会显示
4. 对于非前后分离的项目来说,菜单权限控制比较简单;对于前后分离的菜单不能直接使用到thymeleaf中对于security的支持,需要自定处理权限管理
三、thymeleaf解决csrf
- 在 /templates/ 中新增 login.html,添加隐藏域name值为 _csrf
<!DOCTYPE html>
<html lang="zh"
xmlns:th="http://www.thymeleaf.org"
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5">
<head>
<meta charset="UTF-8">
<title>系统登录</title>
</head>
<body>
<form action="/login" method="post">
用户名:<input type="text" name="username" value="admin" /><br/>
密码:<input type="password" name="password" value="tianxin" /><br/>
<input type="hidden" th:value="${_csrf.token}" name="_csrf" th:if="${_csrf}"/>
记住我:<input type="checkbox" name="remember-me" value="true" /><br/>
<input type="submit" value="登录"/>
</form>
</body>
</html>
- 添加在controller中添加转化请求
@RequestMapping("/csrfLogin")
public String csrfLogin() {
return "login";
}
- 在登录控制中需要放行 /csrfLogin 路径的访问
http.authorizeRequests()
// csrf登录放行
.antMatchers("/csrfLogin").permitAll();
- 安全配置类中注释掉csrf相关代码
// 关闭csrf保护
// http.csrf().disable();
- 使用csrfLogin访问登录页面,正常输入账号和密码之后系统正常登录
- http://localhost:8888/csrfLogin