【RuoYi-Vue-Plus】学习笔记 31 - Sa-Token(五)登录验证拦截器之 Token 有效期及其续签(Sa-Token 源码)
分析Sa-Token登录验证拦截器,Token有效期及其续签。
前言
前几天在群里面聊到关于 token 续签的问题,这个在 Sa-Token 官方文档也有相应的说明,这篇文章还是从源码角度去看看到底做了什么。
参考目录
框架集成
基于 Sa-Token 最新版本
yaml 配置文件
这里需要关注的是两个 timeout 配置:
Sa-Token 配置 SaTokenConfig
注册拦截器
SaTokenConfig#addInterceptors
这里重点关注 StpUtil.checkLogin()
这个方法,其他的会放在后面扩展去简单进行讨论。
功能调用流程分析
关于 StpUtil.checkLogin()
底层的调用过程比较简单容易理解,所以没有画流程图。
从上面 SaTokenConfig#addInterceptors
开始进入,到 StpUtil#checkLogin
:
再深入一层,到 StpLogic#checkLogin
:
然后到今天的主角 StpLogic#getLoginId()
。
1、获取当前会话账号id StpLogic#getLoginId()
注释都写得很明白了,先是进行各种判断,如果全部通过了,来到最后两个方法:
- 检查是否临时过期
这里的checkActivityTimeout
检查的值对应的是配置文件中的activity-timeout
属性值。 - 判断是否自动续签
续签的时间也是对应的是配置文件中的activity-timeout
属性值。
1.1、检查 token 是否已经临时过期 StpLogic#checkActivityTimeout
1.1.1、计算过期时间 StpLogic#getTokenActivityTimeoutByToken
1.2、已过期抛出异常 NotLoginException
(Token已过期)
全局异常处理 GlobalExceptionHandler#handleNotLoginException
:
控制台输出:
1.3、未过期,完成验证
未过期则打上检查标记,完成验证。
2、续签 StpLogic#updateLastActivityToNow
续签实际上就是更新缓存中的最后操作时间为当前时间。
3、完成所有步骤,返回 loginId
至此,拦截器登录检查完成。
扩展分析
扩展1、关于手动续签
图源 Sa-Token 官方文档:
官方提供了手动续签的方法,底层也是调用了上面续签的方法 StpLogic#updateLastActivityToNow
。
值得注意的是,手动续签的时候如果判断 token 临时有效期过期了,依然可以续签成功,因为续签方法是单独的,并没有判断 token 的状态。换句话说,如果捕获到 NotLoginException
异常,那么可以在 catch 中进行手动续签。
这样的话依然可以返回正确结果,而非抛出 401 异常。
扩展2、为什么需要两个 timeout ?
关于这个问题,我询问了一下 狮子大佬 ,他说得比较详细,我直接贴出来:
扩展3、关于 [存储器] 包装类 SaStorage
在前面 1.1、检查 token 是否已经临时过期
里面的方法有用到这个对象(存取检查标记),所以拿出来说一下。
通过查找源码可以得知这个对象是一开始被 Spring 加载到容器中的,本质上就是一个 Servletcontext
对象。
先从 1.1 方法 StpLogic#checkActivityTimeout
回溯:
调用方法 SaStorage storage = SaHolder.getStorage();
SaManager#getSaTokenContextOrSecond
Sa-Token 上下文处理器 SaTokenContext
关于 SaTokenContext
官方文档 也有作介绍:
最后一段话很重要,继续找源头:
至此可知 SaStorage
的完整创建流程。
扩展4、登录接口中 SaStorage
使用
在之前登录接口中也有用到这个对象,因此可以在这里也整理一下。StpLogic#login
StpLogic#setTokenValueToStorage
扩展5、设置注解允许匿名访问的url ExcludeUrlProperties
在配置拦截器时需要排除指定的路径,如下:
参考 框架wiki ,主要有两个途径:
- yaml 配置文件
- 配置
@Anonymous
注解
第一种比较简单,直接读取配置文件,我们聊聊第二种。
ExcludeUrlProperties
这个类是懒加载方式,第一次请求的时候才会将所有需要过滤的请求放到数组 excludes
中(RequestMappingHandlerMapping
能获取到容器中所有请求的方法),并且只会加载一次。
这里会对 /demo/demo/{id}
这种路径进行替换变成 /demo/demo/*
。
但是要注意路径要唯一,否则会把同级别其他路径一起进行过滤:
更多推荐
所有评论(0)