共计 2984 个字符,预计需要花费 8 分钟才能阅读完成。
异常解析与触发场景
NotLoginException是 Sa-Token 中最常见的异常之一,字面意思是 ” 未登录异常 ”。当框架在请求中未能读取到有效 token 时就会抛出这个异常。根据日常开发经验,主要会在以下场景触发:

- 用户未登录直接访问需要认证的接口
- Token 已过期(默认有效期 30 分钟)
- Token 被手动删除或服务端主动注销
- 从不同设备登录导致前一个 token 失效
- Token 在传输过程中被篡改
Token 存储方案对比
Sa-Token 支持多种 token 存储方式,最常见的是通过 Cookie 和 Header 传递:
- Cookie 方式
- 优点:自动携带,无需前端处理
- 缺点:受同源策略限制,跨域需要额外配置
-
配置示例:
@Bean public SaTokenConfig saTokenConfig() {SaTokenConfig config = new SaTokenConfig(); config.setTokenStyle("simple"); config.setTokenName("satoken"); // Cookie 名称 config.setTimeout(30 * 60); // 30 分钟 return config; } -
Header 方式
- 优点:适合前后端分离项目
- 缺点:需要前端显式处理
- 配置示例(在 application.yml 中):
sa-token: token-name: Authorization is-read-header: true
完整异常处理方案
1. 全局异常拦截
Spring Boot 中统一处理异常:
@RestControllerAdvice
public class GlobalExceptionHandler {@ExceptionHandler(NotLoginException.class)
public Result handlerNotLoginException(NotLoginException e) {
// 根据异常子类型细化提示
String message = "";
switch(e.getType()) {
case NotLoginException.INVALID_TOKEN:
message = "Token 无效"; break;
case NotLoginException.TOKEN_TIMEOUT:
message = "Token 已过期"; break;
default:
message = "请先登录";
}
return Result.error(401, message);
}
}
2. Token 生成与刷新
登录接口示例:
@PostMapping("/login")
public Result login(@RequestBody LoginDTO dto) {
// 1. 验证账号密码...
// 2. 生成 token
StpUtil.login(dto.getUserId());
// 3. 返回 token 信息
return Result.success("登录成功", StpUtil.getTokenInfo());
}
3. 自定义登录校验
可以继承 StpInterface 实现权限加载逻辑:
@Component
public class StpInterfaceImpl implements StpInterface {
@Override
public List<String> getPermissionList(Object loginId, String loginType) {// 返回用户权限列表}
@Override
public List<String> getRoleList(Object loginId, String loginType) {// 返回用户角色列表}
}
性能优化建议
- 合理设置过期时间
- 短 token(如 30 分钟)配合长 token(7 天)实现自动续签
-
配置示例:
// 在配置类中设置 config.setTimeout(30 * 60); // 短 token config.setActivityTimeout(24 * 60 * 60); // 长 token -
并发场景处理
- 启用 token 临时缓存(默认已开启)
- 对于高频接口,建议增加本地缓存:
@SaCheckLogin @GetMapping("/userinfo") @Cacheable(value = "user", key = "#userId") public UserInfo getUserInfo(@RequestParam String userId) {// ...}
安全注意事项
- 防止 Token 泄露
- 务必使用 HTTPS 传输
- 不要在前端 JS 中存储 token
-
敏感操作需要二次验证
-
CSRF 防护
- 启用 Sa-Token 的 CSRF 防护:
@Bean public SaTokenConfig saTokenConfig() {SaTokenConfig config = new SaTokenConfig(); config.setTokenName("satoken"); config.setIsReadHeader(true); config.setIsV(true); // 开启 CSRF 防御 return config; }
Spring Boot 集成示例
完整配置类示例:
@Configuration
public class SaTokenConfigure implements WebMvcConfigurer {
// 注册 Sa-Token 配置
@Bean
public SaTokenConfig saTokenConfig() {SaTokenConfig config = new SaTokenConfig();
config.setTokenName("Authorization");
config.setTimeout(30 * 60);
config.setActivityTimeout(-1); // - 1 表示不限制
config.setIsConcurrent(true); // 允许并发登录
config.setIsShare(true); // 共享 token
return config;
}
// 注册拦截器
@Override
public void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new SaAnnotationInterceptor())
.addPathPatterns("/**")
.excludePathPatterns("/login", "/error");
}
}
扩展思考
在实际项目中,我们还需要考虑:
- 分布式环境下的 Token 同步
- 可以结合 Redis 实现 token 集中存储
-
使用 Sa-Token 的分布式模块:
<dependency> <groupId>cn.dev33</groupId> <artifactId>sa-token-redis</artifactId> <version> 最新版本 </version> </dependency> -
多端登录管理
- 通过不同 loginType 区分设备类型
- 示例代码:
// PC 端登录 StpUtil.login(10001, "PC"); // 移动端登录 StpUtil.login(10001, "APP");
通过本文的介绍,相信你已经掌握了 Sa-Token 中 NotLoginException 异常的处理方法。建议在实际项目中根据业务需求灵活调整 token 策略,并在开发过程中做好异常监控和日志记录。
正文完
