共计 1498 个字符,预计需要花费 4 分钟才能阅读完成。
最近在项目中使用 Sa-Token 做权限管理时,频繁遇到 NotLoginException 异常,错误信息显示 未能读取到有效 Token。经过一番排查和优化,终于找到了稳定的解决方案,这里把经验分享给大家。
一、为什么会出现 NotLoginException?
Sa-Token 的 Token 验证机制非常严格,以下情况都会触发这个异常:
- Token 过期:默认 30 分钟无操作就会过期
- 多端登录互踢:新登录会挤掉旧 Token
- 签名篡改:客户端私自修改了 Token 内容
- 服务端重启:内存中的 Token 数据丢失
- 跨服务调用:在微服务环境中未正确传递 Token
二、两种续期方案对比
方案 1:Cookie 续期(传统方案)
- 优点:浏览器自动管理,无需前端配合
- 缺点:移动端兼容性差,存在 CSRF 风险
方案 2:Token 自动刷新(推荐方案)
- 优点:全平台通用,安全性更高
- 缺点:需要前后端配合实现
三、Sa-Token 配置示例
@Configuration
public class SaTokenConfig {
/** 配置 Token 有效期 */
@Bean
public SaTokenConfig getSaTokenConfig() {SaTokenConfig config = new SaTokenConfig();
// 关键配置项
config.setTokenName("satoken");
config.setTimeout(30 * 60); // 30 分钟无操作过期
config.setActivityTimeout(24 * 60 * 60); // 每天续期
config.setIsConcurrent(true); // 允许并发登录
config.setIsShare(true); // 共享 Token
return config;
}
}
四、Token 续期拦截器实现
@Component
public class TokenRenewInterceptor implements SaTokenInterceptor {
@Override
public void preHandle(Object handler) {
// 只有已登录的请求才续期
if(StpUtil.isLogin()) {
// 线程安全续期操作
StpUtil.renewTimeout(30 * 60, TimeUnit.SECONDS);
}
}
}
五、集成 Redis 实现分布式 Token
- 添加依赖:
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-redis</artifactId>
<version>1.34.0</version>
</dependency>
- 配置 Redis 连接:
spring:
redis:
host: 127.0.0.1
port: 6379
# 生产环境建议配置连接池
lettuce:
pool:
max-active: 100
max-wait: -1ms
六、避坑指南
- JWT Token 过长问题:
-
解决方案:启用 Token 压缩
config.setIsCompressToken(true); -
时钟不同步问题:
- 所有服务器必须同步 NTP
- 配置时钟偏移容忍度:
config.setTimeOffset(5 * 60); // 允许 5 分钟误差
七、性能验证结果
使用 JMeter 压测对比:
| 场景 | QPS | 平均响应时间 |
|---|---|---|
| 原始方案 | 1200 | 85ms |
| 优化后方案 | 3500 | 28ms |
内存占用对比(通过 MAT 分析):

八、思考题
当遭遇海量无效 Token 攻击时,除了限流还能如何防御?欢迎在评论区分享你的方案。
通过这套方案,我们成功将系统的 Token 异常率从 3.2% 降到了 0.05%,用户体验得到显著提升。希望对遇到同样问题的同学有所帮助!
正文完
发表至: 未分类
四天前
