掘金 后端 ( ) • 2024-03-06 15:25

theme: scrolls-light

思君令人老,岁月忽已晚 。

1 前言

在前文中已经讲述了Spring-Security 认证流程分析及多方式登录认证实践,在本文中继续分享 spring-security 相关的内容。在项目开发中基本都是前后端分离的方式,通常使用 jwt 方式,上文已经讲述了登录认证的实践,本文将在此基础上继续进行权限配置的分享。

2 jwt

JWT 用于登录身份验证,用户成功登录后会根据用户信息生成一个 token 返回给客户端,其中包含用户信息,客户端每次请求都要在请求头 Authorization 上携带 token 信息,后端服务拿到 token 信息后,通过 secretKey 解密信息进行身份验证。JWT 生成的 Token 由三部分组成:

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 是否过期?首先我们需要先引入对应的依赖,如下所示:

<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.9.1</version>
</dependency>

创建 token 的方法以及解析 tokenjava 对象的方法如下图所示,在解析 token 时加入了其过期时间的判断,当 token 过期时会抛出自定义异常。 图片.png

3 spring-security 整合 jwt

前文已经介绍了 jwt 的内容,结合 spring-security 来使用的话,首先需要创建一个过滤器,将其配置在 security 配置中。

创建过滤器如下所示,实践证明一下两者都可以,前者也是继承了后者,在其基础上增加了认证的内容:

# spring-security 提供的认证拦截过滤器
BasicAuthenticationFilter
# spring 提供的过滤器 
OncePerRequestFilter

过滤器的任务便是从请求中获取 token 信息并进行解析,放入 Authentication 中并设置到 Security 上下文对象中,解析和验证 token 的流程使用 JwtUtils 提供的静态方法来完成。 图片.png

如下图所示,即 security 的认证配置,在这里设置了两个登录地址,/login 使用 security 自带的登录认证方式,/login/user 使用自定义认证登录。前者使用 form 表单的方式进行登录认证在认证成功处理器中生成 token ,而自定义登录地址的方式在登录方法中生成 token , 两者都是通过 authenticate.getPrincipal() 的方式来获取用户信息。后者在功能扩展上十分方便。

图片.png

两者的编码如下图所示: 图片.png

4 权限配置

在 jwt 认证通过之后,就需要对登录用户赋予相应的角色和权限,以便用户查看各类权限的资源。通常情况下,一个用户会拥有多个角色,一个角色会拥有多个权限。具体如下图所示: 图片.png

spring-securityspringboot 中的权限拦截是通过以下注解来实现的,都是使用在方法级别上:

@PreAuthorize, 在方法请求之前进行鉴权
@PostAuthorize,在方法请求之后进行鉴权
@PreFilter, 过滤请求之前的集合参数
@PostFilter 过滤方法返回值,针对的是集合对象

通常情况下,使用的是 @PreAuthorize 注解,在方法之前之前进行鉴权。如下图所示,进行鉴权的方法有 has(Any)Role、 has(Any)Authority、 hasPermission 鉴权是通过 PermissionEvaluator 来处理的。

图片.png

如下图所示,使用的是 @PreAuthorize,分别使用自带鉴权和自定义鉴权方法,自定义鉴权是通过角色来进行判断。自定义权限可以使用角色也可以使用权限,通常来说是通过权限来精细判断。 图片.png

如果使用 spring-security 扩展权限认证时,需要重写 PermissionEvaluator,然后在配置中添加 DefaultWebSecurityExpressionHandler,如图右所示,采用这样的方式也可以设置角色的前缀,或者去掉前缀也可以。 1706878257385.png

相对而言,通过自定义的方式实现权限相对简单,实现方式如下图所示,可以不用实现接口 PermissionEvaluator,但是通过此种方法实现需要在使用时添加 @ 符号才能够生效。 1706879133566.png

三种方式的使用方式如下图所示,这里之所以能实现鉴权,是 spring-el 表达式来实现这样的鉴权方式。 1706880766824.png

6 总结

本文主要介绍了 spring security jwt 配置以及登录之后的鉴权,并以此为基础实践了多种方式的登录以及自定义鉴权,spring security 作为系统开发中常用的权限认证框架, jwt 方式在前后端分离项目中有着广泛的运用 。所涉及的代码已经上传至 gitee, 欢迎大家点赞关注。项目 gitee 地址 springsecurity-learn