Sa-Token多账号认证与权限控制实践指南
1. Sa-Token多账号认证体系设计在后台管理系统开发中多账号类型并存是常见需求。Admin账号通常拥有系统所有权限而User账号只能访问特定功能模块。Sa-Token通过灵活的鉴权设计可以完美支持这种多角色并存的场景。1.1 核心架构设计Sa-Token的多账号认证体系基于以下核心组件构建账号体系隔离通过StpUtil和StpAdminUtil两套API分别管理User和Admin账号会话独立管理两种账号类型使用不同的token前缀和存储空间权限校验分离通过SaCheckLogin和SaCheckRole等注解实现差异化鉴权典型配置示例// 配置Admin账号参数 Configuration public class SaTokenAdminConfig { Autowired public void configAdmin(SaTokenConfig config) { config.setTokenName(satoken-admin) .setTimeout(30 * 24 * 60 * 60); // 30天超时 } } // 配置User账号参数 Configuration public class SaTokenUserConfig { Autowired public void configUser(SaTokenConfig config) { config.setTokenName(satoken-user) .setTimeout(2 * 60 * 60); // 2小时超时 } }1.2 登录认证实现对于多账号系统登录流程需要区分账号类型// Admin登录 PostMapping(/admin/login) public SaResult adminLogin(String username, String password) { if(admin.equals(username) 123456.equals(password)) { StpAdminUtil.login(10001); // 为Admin账号10001创建会话 return SaResult.ok(管理员登录成功); } return SaResult.error(管理员登录失败); } // User登录 PostMapping(/user/login) public SaResult userLogin(String username, String password) { User user userService.selectByUsername(username); if(user ! null user.getPassword().equals(password)) { StpUtil.login(user.getId()); // 为User账号创建会话 return SaResult.ok(用户登录成功); } return SaResult.error(用户登录失败); }关键点两种账号类型使用完全独立的会话管理即使ID相同也不会冲突2. 权限控制实现细节2.1 角色权限分配在Sa-Token中可以通过以下方式为不同账号类型分配权限// 为Admin账号添加角色和权限 StpAdminUtil.getRoleList(10001); // 返回[super-admin, content-admin] StpAdminUtil.getPermissionList(10001); // 返回[*] // 为User账号添加角色和权限 StpUtil.getRoleList(20001); // 返回[member] StpUtil.getPermissionList(20001); // 返回[user:info, order:list]权限配置建议采用RBAC模型创建admin_role、user_role等基础角色为角色分配对应权限点将用户与角色关联2.2 接口鉴权方案Sa-Token提供多种鉴权方式适合不同场景注解式鉴权推荐// Admin专属接口 SaCheckLogin(type StpAdminUtil.TYPE) GetMapping(/admin/dashboard) public SaResult adminDashboard() { return SaResult.data(管理员仪表盘数据); } // User专属接口 SaCheckRole(value member, type StpUtil.TYPE) GetMapping(/user/profile) public SaResult userProfile() { return SaResult.data(用户个人信息); }编程式鉴权// 校验Admin登录 if(!StpAdminUtil.isLogin()) { throw new ApiException(请先登录管理员账号); } // 校验User权限 if(!StpUtil.hasPermission(order:create)) { throw new ApiException(没有订单创建权限); }路由拦截鉴权Configuration public class SaTokenConfigure implements WebMvcConfigurer { Override public void addInterceptors(InterceptorRegistry registry) { // 注册Admin拦截器 registry.addInterceptor(new SaInterceptor(handle - { SaRouter.match(/admin/**).check(r - StpAdminUtil.checkLogin()); })).addPathPatterns(/admin/**); // 注册User拦截器 registry.addInterceptor(new SaInterceptor(handle - { SaRouter.match(/user/**).check(r - StpUtil.checkLogin()); })).addPathPatterns(/user/**); } }3. 高级功能实现3.1 同账号类型多端登录对于需要支持同一账号在PC、APP等多端登录的场景// 启用多端登录默认配置 StpUtil.config.setIsConcurrent(true); // 获取当前账号所有登录的设备 ListString tokenList StpUtil.getTokenValueListByLoginId(10001); // 强制下线指定设备 StpUtil.kickoutByTokenValue(xxxxxx);3.2 临时权限提升某些场景下需要临时提升User账号权限// 1. 添加临时权限 StpUtil.addPermission(20001, admin:temp); // 有效期默认30分钟 // 2. 使用临时权限 SaCheckPermission(admin:temp) public void adminOperation() { // 临时管理员操作 } // 3. 清除临时权限 StpUtil.clearPermission(20001);3.3 安全防护措施Token防盗用// 启用Token绑定设备指纹 StpUtil.config.setBindDevice(true); // 校验Token所属设备 StpUtil.checkDevice(PC-001);定期刷新机制// 配置自动续期在过期前1小时触发 StpUtil.config.setAutoRenew(true) .setRenewTimeout(60 * 60);敏感操作二次验证// 发送验证码 smsService.sendVerifyCode(StpUtil.getLoginId()); // 校验验证码 SaCheckSafe(password 123456, device PC-001) PostMapping(/user/changePassword) public SaResult changePassword(String newPwd) { // 修改密码逻辑 }4. 实战问题解决方案4.1 常见问题排查问题现象可能原因解决方案Admin接口返回未登录使用了StpUtil而非StpAdminUtil统一使用StpAdminUtil管理Admin会话权限校验不生效注解type参数配置错误确认SaCheckRole(type StpUtil.TYPE)正确Token频繁失效多端登录冲突配置setIsConcurrent(true)或限制登录设备数接口访问403权限点未正确分配检查权限树配置和用户角色关联4.2 性能优化建议缓存策略优化// 使用Redis集群模式 SaTokenConfig config new SaTokenConfig() .setTokenStyle(uuid) .setCache(new SaTokenCacheRedisCluster(redisClusterNodes));权限缓存加载// 登录时预加载权限数据 StpUtil.login(10001, new SaLoginModel() .setExtraData(permissions, getPermissionList(10001)) );批量鉴权处理// 批量校验权限减少Redis访问 ListBoolean results StpUtil.hasPermissionList( Arrays.asList(user:add, user:delete, user:update) );4.3 微服务场景适配在Spring Cloud微服务体系中网关统一鉴权// 全局过滤器 public class AuthFilter implements GlobalFilter { Override public MonoVoid filter(ServerWebExchange exchange, GatewayFilterChain chain) { // Admin路由校验 if(path.startsWith(/admin/)) { StpAdminUtil.checkLogin(); } // User路由校验 else if(path.startsWith(/user/)) { StpUtil.checkLogin(); } return chain.filter(exchange); } }Feign调用鉴权// 自动添加Token Bean public RequestInterceptor requestInterceptor() { return template - { if(StpUtil.isLogin()) { template.header(satoken, StpUtil.getTokenValue()); } }; }在实际项目中我们团队通过Sa-Token实现了包含5种账号类型超级管理员、部门管理员、审计员、普通用户、访客的复杂权限体系。关键经验包括每种账号类型使用独立的StpUtil实例权限树设计采用模块:操作的命名规范如user:add敏感操作日志记录登录ID和操作时间定期审计权限分配情况对于高并发场景建议使用Redis集群部署会话存储权限数据采用本地缓存Redis二级缓存频繁访问的接口添加SaCheckSafe提升安全性