思君令人老,岁月忽已晚 。
1 前言
在前文中已经讲述了Spring-Security 认证流程分析及多方式登录认证实践,在本文中继续分享 spring-security
相关的内容。在项目开发中基本都是前后端分离的方式,通常使用 jwt
方式,上文已经讲述了登录认证的实践,本文将在此基础上继续进行权限配置的分享。
2 jwt
JWT
用于登录身份验证,用户成功登录后会根据用户信息生成一个 token
返回给客户端,其中包含用户信息,客户端每次请求都要在请求头 Authorization
上携带 token
信息,后端服务拿到 token
信息后,通过 secretKey
解密信息进行身份验证。JWT
生成的 Token
由三部分组成:
less
JWT由三部分组成:header(头部)、payload(载荷)、signature(签名)
JWT的格式为:header.payload.signature, 都是通过 base64进行编码
header
alg 指定 signature 采用的加密算法,默认是 HS256, 对称加密算法,也可以使用非对称加密算法 RS256
typ 固定值为 jwt
payload
用户信息,令牌签发时间,令牌过期时间
signature
设置 secretkey, 将 header 和 payload 的结果进行合并,使用HS256算法合并计算
signature = HS256(baseUrl64(header)+'.'+baseUrl(payload)+','+secretKey)
上面介绍了 jwt
的结构,那怎么使用 jwt
生成 token
, 并且怎么解析 token
呢,怎么判断 token
是否过期?首先我们需要先引入对应的依赖,如下所示:
xml
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
创建 token
的方法以及解析 token
成 java
对象的方法如下图所示,在解析 token
时加入了其过期时间的判断,当 token
过期时会抛出自定义异常。
3 spring-security 整合 jwt
前文已经介绍了 jwt
的内容,结合 spring-security
来使用的话,首先需要创建一个过滤器,将其配置在 security
配置中。
创建过滤器如下所示,实践证明一下两者都可以,前者也是继承了后者,在其基础上增加了认证的内容:
arduino
# spring-security 提供的认证拦截过滤器
BasicAuthenticationFilter
# spring 提供的过滤器
OncePerRequestFilter
过滤器的任务便是从请求中获取 token
信息并进行解析,放入 Authentication
中并设置到 Security
上下文对象中,解析和验证 token
的流程使用 JwtUtils 提供的静态方法来完成。
如下图所示,即 security
的认证配置,在这里设置了两个登录地址,/login
使用 security
自带的登录认证方式,/login/user
使用自定义认证登录。前者使用 form
表单的方式进行登录认证在认证成功处理器中生成 token
,而自定义登录地址的方式在登录方法中生成 token
, 两者都是通过 authenticate.getPrincipal()
的方式来获取用户信息。后者在功能扩展上十分方便。
两者的编码如下图所示:
4 权限配置
在 jwt 认证通过之后,就需要对登录用户赋予相应的角色和权限,以便用户查看各类权限的资源。通常情况下,一个用户会拥有多个角色,一个角色会拥有多个权限。具体如下图所示:
spring-security
在 springboot
中的权限拦截是通过以下注解来实现的,都是使用在方法级别上:
less
@PreAuthorize, 在方法请求之前进行鉴权
@PostAuthorize,在方法请求之后进行鉴权
@PreFilter, 过滤请求之前的集合参数
@PostFilter 过滤方法返回值,针对的是集合对象
通常情况下,使用的是 @PreAuthorize
注解,在方法之前之前进行鉴权。如下图所示,进行鉴权的方法有 has(Any)Role、 has(Any)Authority、 hasPermission
鉴权是通过 PermissionEvaluator
来处理的。
如下图所示,使用的是 @PreAuthorize
,分别使用自带鉴权和自定义鉴权方法,自定义鉴权是通过角色来进行判断。自定义权限可以使用角色也可以使用权限,通常来说是通过权限来精细判断。
如果使用 spring-security
扩展权限认证时,需要重写 PermissionEvaluator
,然后在配置中添加 DefaultWebSecurityExpressionHandler
,如图右所示,采用这样的方式也可以设置角色的前缀,或者去掉前缀也可以。
相对而言,通过自定义的方式实现权限相对简单,实现方式如下图所示,可以不用实现接口 PermissionEvaluator
,但是通过此种方法实现需要在使用时添加 @
符号才能够生效。
三种方式的使用方式如下图所示,这里之所以能实现鉴权,是 spring-el
表达式来实现这样的鉴权方式。
6 总结
本文主要介绍了 spring security jwt
配置以及登录之后的鉴权,并以此为基础实践了多种方式的登录以及自定义鉴权,spring security
作为系统开发中常用的权限认证框架, jwt
方式在前后端分离项目中有着广泛的运用 。所涉及的代码已经上传至 gitee
, 欢迎大家点赞关注。项目 gitee
地址 springsecurity-learn。