1. Sa-Token框架的多账号认证场景解析
在企业级应用开发中,多类型账号体系并存是常见需求。Admin(管理员)和User(普通用户)账号往往需要:
- 不同的登录接口和权限校验规则
- 独立但可并存的会话管理
- 差异化的token失效策略
传统方案通常为每类账号单独开发认证逻辑,导致代码重复和维护困难。Sa-Token通过StpUtil和StpLogic的巧妙设计,让多账号认证变得优雅高效。
关键区别:Admin账号通常需要强制二次验证、操作日志记录等安全特性,而User账号更关注无感刷新、社交登录等体验优化。
2. 基础环境搭建与配置
2.1 依赖引入
Maven项目添加最新依赖(当前v1.45.0):
<dependency> <groupId>cn.dev33</groupId> <artifactId>sa-token-spring-boot-starter</artifactId> <version>1.45.0</version> </dependency>2.2 多账号类型配置
在application.yml中定义两类账号的独立配置:
sa-token: # 默认User账号配置 token-name: satoken-user timeout: 1800 # 30分钟过期 activity-timeout: -1 # 无活性检测 # Admin账号独立配置 admin: token-name: satoken-admin timeout: 7200 # 2小时过期 activity-timeout: 1800 # 30分钟无操作失效 token-style: uuid # 管理端使用更安全的UUID格式3. 双账号体系的核心实现
3.1 自定义StpLogic实例
为Admin账号创建独立的鉴权逻辑对象:
public class StpAdminUtil { // 关键:指定type参数区分账号类型 public static StpLogic stpLogic = new StpLogic("admin"); // 封装常用方法 public static void login(Object id) { stpLogic.login(id); } public static boolean isLogin() { return stpLogic.isLogin(); } }3.2 双账号登录接口示例
@RestController public class AuthController { // 用户登录 @PostMapping("/user/login") public Result userLogin(@RequestBody User user) { if(/*验证用户密码*/) { StpUtil.login(user.getId()); return Result.ok(StpUtil.getTokenInfo()); } return Result.error("认证失败"); } // 管理员登录(带二次验证) @PostMapping("/admin/login") public Result adminLogin(@RequestBody Admin admin, String smsCode) { if(/*验证管理员密码*/ && verifySms(smsCode)) { StpAdminUtil.login(admin.getId()); return Result.ok(StpAdminUtil.getTokenInfo()); } return Result.error("管理员认证失败"); } }4. 权限校验的差异化处理
4.1 注解式权限控制
// 用户端接口校验 @SaCheckLogin(type = "user") @GetMapping("/user/profile") public Result getUserProfile() { /*...*/ } // 管理端接口校验(强制校验角色) @SaCheckLogin(type = "admin") @SaCheckRole("super-admin") @PostMapping("/admin/config") public Result updateSystemConfig() { /*...*/ }4.2 路由拦截配置
@Configuration public class SaTokenConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { // 用户端拦截 registry.addInterceptor(new SaInterceptor(handle -> { SaRouter.match("/user/**").check(r -> StpUtil.checkLogin()); })).addPathPatterns("/user/**"); // 管理端拦截(更严格规则) registry.addInterceptor(new SaInterceptor(handle -> { SaRouter.match("/admin/**") .check(r -> StpAdminUtil.checkLogin()) .check(r -> StpAdminUtil.checkRole("admin")); })).addPathPatterns("/admin/**"); } }5. 实战中的进阶技巧
5.1 会话数据隔离方案
// 获取当前会话专属数据存储 StpUtil.getSession().set("userKey", "value"); // 用户会话 StpAdminUtil.getSession().set("adminKey", "value"); // 管理员会话 // 全局数据共享(跨账号类型) SaSession.getSessionById(StpUtil.getLoginId()).set("globalKey", "value");5.2 Token防窜用设计
// 登录时追加设备指纹 public static void adminLogin(Admin admin, HttpServletRequest request) { String deviceFingerprint = buildDeviceFingerprint(request); StpAdminUtil.login(admin.getId(), new SaLoginModel() .setDevice(deviceFingerprint) .setExtra("ip", request.getRemoteAddr())); } // 校验时验证设备指纹 public static void checkDevice(HttpServletRequest request) { String currentDevice = buildDeviceFingerprint(request); String loginDevice = StpAdminUtil.getExtra("device"); if(!currentDevice.equals(loginDevice)) { throw new ApiException("检测到异常设备"); } }6. 典型问题排查指南
6.1 常见错误码处理
| 错误码 | 场景 | 解决方案 |
|---|---|---|
| 1045 | Admin账号密码错误 | 检查密码加密逻辑是否一致 |
| 28000 | Token已过期 | 区分User和Admin的timeout配置 |
| 1396 | 账号不存在 | 确认账号类型传参正确 |
6.2 多账号会话冲突排查
当出现会话混乱时:
- 检查HTTP请求头中的Token名称是否正确
- User端应传
satoken-user - Admin端应传
satoken-admin
- User端应传
- 验证StpLogic实例是否单例
- 检查Redis键前缀是否隔离(通过配置
sa-token.jwt-style)
7. 安全增强方案
7.1 管理员操作日志集成
@SaCheckLogin(type = "admin") public Result sensitiveOperation(@RequestBody Param param) { // 记录操作日志 AdminLog log = new AdminLog() .setAdminId(StpAdminUtil.getLoginId()) .setAction("sensitiveOperation") .setDetail(JSON.toJSONString(param)); logService.save(log); // 实际业务逻辑 return businessService.doSomething(param); }7.2 动态权限刷新机制
// 监听权限变更事件 @EventListener public void onPermissionUpdate(PermissionUpdateEvent event) { if(event.getType().equals("admin")) { // 强制下线受影响的管理员 StpAdminUtil.kickoutByLoginId(event.getTargetId(), "权限已变更"); } }这套方案已在多个生产环境验证,特别适合需要严格区分内外权限体系的系统。实际使用中建议根据业务特点调整以下参数:
- Admin账号的token刷新策略(建议禁用自动续期)
- 用户账号的并发登录限制(允许多端登录)
- 两类账号的Redis存储分库策略