前几天在群里面聊到关于 token 续签的问题,这个在 Sa-Token 官方文档也有相应的说明,这篇文章还是从源码角度去看看到底做了什么。

这里需要关注的是两个 timeout 配置:

SaTokenConfig 注册拦截器SaTokenConfig#addInterceptors

这里重点关注 StpUtil.checkLogin() 这个方法,其他的会放在后面扩展去简单进行讨论。
关于 StpUtil.checkLogin() 底层的调用过程比较简单容易理解,所以没有画流程图。
从上面 SaTokenConfig#addInterceptors 开始进入,到 StpUtil#checkLogin :

再深入一层,到 StpLogic#checkLogin:

然后到今天的主角 StpLogic#getLoginId()。
StpLogic#getLoginId()
注释都写得很明白了,先是进行各种判断,如果全部通过了,来到最后两个方法:
checkActivityTimeout 检查的值对应的是配置文件中的 activity-timeout 属性值。activity-timeout 属性值。StpLogic#checkActivityTimeout
StpLogic#getTokenActivityTimeoutByToken
NotLoginException (Token已过期)
全局异常处理 GlobalExceptionHandler#handleNotLoginException:

控制台输出:

未过期则打上检查标记,完成验证。

StpLogic#updateLastActivityToNow
续签实际上就是更新缓存中的最后操作时间为当前时间。


至此,拦截器登录检查完成。
图源 Sa-Token 官方文档:
官方提供了手动续签的方法,底层也是调用了上面续签的方法 StpLogic#updateLastActivityToNow 。
值得注意的是,手动续签的时候如果判断 token 临时有效期过期了,依然可以续签成功,因为续签方法是单独的,并没有判断 token 的状态。换句话说,如果捕获到 NotLoginException 异常,那么可以在 catch 中进行手动续签。

这样的话依然可以返回正确结果,而非抛出 401 异常。
关于这个问题,我询问了一下 狮子大佬 ,他说得比较详细,我直接贴出来:
SaStorage在前面 1.1、检查 token 是否已经临时过期 里面的方法有用到这个对象(存取检查标记),所以拿出来说一下。
通过查找源码可以得知这个对象是一开始被 Spring 加载到容器中的,本质上就是一个 Servletcontext 对象。
先从 1.1 方法 StpLogic#checkActivityTimeout 回溯:
调用方法 SaStorage storage = SaHolder.getStorage();

SaManager#getSaTokenContextOrSecond

Sa-Token 上下文处理器 SaTokenContext

关于 SaTokenContext 官方文档 也有作介绍:
最后一段话很重要,继续找源头:



至此可知 SaStorage 的完整创建流程。
SaStorage 使用在之前登录接口中也有用到这个对象,因此可以在这里也整理一下。
StpLogic#login

StpLogic#setTokenValueToStorage

ExcludeUrlProperties在配置拦截器时需要排除指定的路径,如下:

参考 框架wiki ,主要有两个途径:

@Anonymous 注解
第一种比较简单,直接读取配置文件,我们聊聊第二种。
ExcludeUrlProperties

这个类是懒加载方式,第一次请求的时候才会将所有需要过滤的请求放到数组 excludes 中(RequestMappingHandlerMapping 能获取到容器中所有请求的方法),并且只会加载一次。
这里会对 /demo/demo/{id} 这种路径进行替换变成 /demo/demo/*。


但是要注意路径要唯一,否则会把同级别其他路径一起进行过滤: