权限认证是每个后台系统都绕不过去的功能。Shiro 配置繁琐、Spring Security 学习曲线陡峭。Sa-Token 是一个轻量级的 Java 权限认证框架,API 设计简洁,几行代码就能集成到 SpringBoot 中。
一、Sa-Token 简介
相比 Spring Security 和 Shiro,Sa-Token 最大的优势就是简单:
| 功能 | Sa-Token | Shiro | Spring Security |
|---|---|---|---|
| 登录认证 | StpUtil.login() | Subject.login() | 复杂配置 |
| 权限校验 | @SaCheckPermission | 配置繁琐 | @PreAuthorize |
| 踢人下线 | StpUtil.kickout() | 需要自己实现 | 需要自己实现 |
| Redis 集成 | 加配置一行 | 要写代码 | 默认支持 |
核心特点:零配置、API 简单、内置 Redis 集成、支持 OAuth2。
二、快速集成
1. 引入依赖
<dependency><groupId>cn.dev33</groupId><artifactId>sa-token-spring-boot-starter</artifactId><version>1.37.0</version></dependency>2. 配置(application.yml)
sa-token:# token 名称(默认 satoken)token-name:token# token 有效期(秒,30天)timeout:2592000# token 最低活跃频率(秒,-1 不续签)active-timeout:-1# 是否允许同一账号多地同时登录(true 允许多端登录)is-concurrent:true# 多人登录时,是否踢掉已登录的(false 不踢)is-share:false# token 风格token-style:uuid# 是否输出操作日志is-log:true就这么两配置,不需要别的 XML 或配置类。
三、登录认证
@RestController@RequestMapping("/auth")publicclassAuthController{/** * 登录接口 */@PostMapping("/login")publicResultVO<String>login(@RequestParamStringusername,@RequestParamStringpassword){// 校验用户名密码(这里以 admin/123456 为例)if(!"admin".equals(username)||!"123456".equals(password)){returnResultVO.error(401,"用户名或密码错误");}// 执行登录(Sa-Token 自动生成 token)StpUtil.login(1001);// 参数为用户ID// 获取 token 返回给前端Stringtoken=StpUtil.getTokenInfo().getTokenValue();returnResultVO.success(token);}/** * 退出登录 */@PostMapping("/logout")publicResultVO<?>logout(){StpUtil.logout();returnResultVO.success("退出成功");}/** * 获取当前登录用户信息 */@GetMapping("/info")publicResultVO<?>info(){// 获取当前用户IDlonguserId=StpUtil.getLoginIdAsLong();returnResultVO.success("当前用户: "+userId);}}前端请求时在 header 中携带 token:
Authorization: satoken Content-Type: application/json四、拦截器配置(需要登录才能访问)
@ConfigurationpublicclassSaTokenConfigimplementsWebMvcConfigurer{@OverridepublicvoidaddInterceptors(InterceptorRegistryregistry){// 注册 Sa-Token 的路由拦截器registry.addInterceptor(newSaInterceptor()).addPathPatterns("/**").excludePathPatterns("/auth/login",// 登录接口不拦截"/auth/register","/doc.html",// Swagger 文档"/v3/**","/swagger-ui/**");}}配置后,所有未登录的请求会返回401 未登录,不需要自己写拦截器。
五、权限认证
1. 给用户分配权限
@ServicepublicclassUserService{/** * 获取用户的权限列表(从数据库查询) */publicList<String>getPermissions(LonguserId){// 实际项目中从数据库查询if(userId==1001){returnArrays.asList("user.add","user.delete","user.update","user.query");}returnArrays.asList("user.query");}/** * 获取用户的角色列表 */publicList<String>getRoles(LonguserId){if(userId==1001){returnArrays.asList("admin");}returnArrays.asList("user");}}2. 注册权限接口
@ComponentpublicclassStpInterfaceImplimplementsStpInterface{@AutowiredprivateUserServiceuserService;/** * 获取用户的权限列表(框架自动调用) */@OverridepublicList<String>getPermissionList(ObjectloginId,StringloginType){LonguserId=Long.parseLong(loginId.toString());returnuserService.getPermissions(userId);}/** * 获取用户的角色列表 */@OverridepublicList<String>getRoleList(ObjectloginId,StringloginType){LonguserId=Long.parseLong(loginId.toString());returnuserService.getRoles(userId);}}3. 使用注解控制权限
@RestController@RequestMapping("/user")publicclassUserController{@GetMapping("/list")@SaCheckPermission("user.query")// 需要 user.query 权限publicResultVO<?>list(){returnResultVO.success("查询用户列表");}@PostMapping("/add")@SaCheckPermission("user.add")// 需要 user.add 权限publicResultVO<?>add(){returnResultVO.success("新增用户");}@DeleteMapping("/delete")@SaCheckPermission("user.delete")// 需要 user.delete 权限publicResultVO<?>delete(){returnResultVO.success("删除用户");}@PutMapping("/update")@SaCheckPermission("user.update")// 需要 user.update 权限publicResultVO<?>update(){returnResultVO.success("修改用户");}}4. 角色校验
@GetMapping("/admin/dashboard")@SaCheckRole("admin")// 只有 admin 角色能访问publicResultVO<?>dashboard(){returnResultVO.success("管理后台面板");}5. 在代码中手动校验
// 校验是否有权限(没有则抛异常)StpUtil.checkPermission("user.add");// 校验权限(返回 boolean)if(StpUtil.hasPermission("user.delete")){// 有权限就执行}// 校验角色StpUtil.checkRole("admin");六、踢人下线
管理员可以强制让某个用户下线(比如检测到异常登录):
@PostMapping("/kickout")@SaCheckRole("admin")publicResultVO<?>kickout(LonguserId){// 让指定用户被踢下线StpUtil.kickout(userId);returnResultVO.success("已强制用户 "+userId+" 下线");}被踢的用户下次请求时会收到401,提示"Token 已被踢下线"。
七、记住我(7天免登录)
// 登录时设置 rememberMe = true,token 有效期自动延长StpUtil.login(1001,true);// 不传或 false 则使用配置的 timeoutStpUtil.login(1001);在配置中设置记住我的时长:
sa-token:# 记住我模式的有效期(单位:秒,7天)activity-timeout:604800八、单点登录(SSO)
Sa-Token 内置了单点登录方案,几行配置就能实现多系统统一登录:
sa-token:sso:# SSO 认证中心地址auth-url:http://sso-server.com:9000/auth# 是否开启单点登录is-sso:true详细用法参考 Sa-Token 官方文档(sso 章节)。
九、与你的秒杀系统集成
@RestController@RequestMapping("/api/seckill")@SaCheckLogin// 整个类需要登录才能访问publicclassSeckillController{@PostMapping("/do/{productId}")@SaCheckPermission("seckill.buy")// 需要秒杀权限publicResultVO<?>doSeckill(@PathVariableLongproductId){// 获取当前登录用户longuserId=StpUtil.getLoginIdAsLong();returnseckillService.doSeckill(productId,userId,"用户"+userId);}}只用加两个注解,权限控制就搞定了。比之前可能用的拦截器+Session 方式省事很多。
十、Sa-Token 常用 API 速查
// 登录认证StpUtil.login(1001);// 登录StpUtil.logout();// 登出StpUtil.getLoginId();// 获取当前用户IDStpUtil.isLogin();// 是否登录StpUtil.checkLogin();// 校验登录(未登录抛异常)// 权限校验StpUtil.checkPermission("user.add");// 校验权限StpUtil.hasPermission("user.add");// 是否拥有权限StpUtil.checkRole("admin");// 校验角色StpUtil.hasRole("admin");// 是否拥有角色// 踢人StpUtil.kickout(1001);// 踢用户下线StpUtil.logout(1001);// 让用户注销(踢下线且清除记录)// Token 管理StpUtil.getTokenValue();// 获取当前 tokenStpUtil.getTokenInfo();// 获取 token 详细信息总结:Sa-Token 的核心就两句话——StpUtil.login()登录,@SaCheckPermission鉴权。比 Shiro 的 Subject + Realm + 配置文件那一套简洁太多了。
💡 觉得有用的话,点赞 + 关注【张老师技术栈】吧!每周更新 Java/Python/爬虫 实战干货,不让你白来。