什么是 Sa-Token?
Sa-Token 是一个轻量级 Java 权限认证框架,主要解决以下一系列权限相关问题:
- 登录认证
- 权限认证
- Session 会话
- 单点登录
- OAuth2.0
- 分布式 Session 会话
- 微服务网关鉴权
Sa-Token 致力于让权限认证变得简单、优雅,开发者可以通过简单的几行代码实现复杂的权限控制功能。
Sa-Token 的核心特性
1. 登录认证
支持多种登录策略:
2. 权限认证
提供灵活的鉴权方式:
- 权限认证
- 角色认证
- 会话二级认证
- 注解鉴权
- 路由鉴权
3. 会话管理
完善的会话管理方案:
4. 微服务支持
开箱即用的微服务认证方案:
- 分布式 Session 会话
- 网关统一鉴权
- RPC 调用鉴权
集成 Sa-Token
Maven 依赖
在 Spring Boot 项目中添加以下依赖:
1 2 3 4 5 6
| <dependency> <groupId>cn.dev33</groupId> <artifactId>sa-token-spring-boot-starter</artifactId> <version>1.38.0</version> </dependency>
|
基本配置
在 application.yml 中添加基本配置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| sa-token: token-name: satoken timeout: 2592000 activity-timeout: -1 is-concurrent: true is-share: true token-style: uuid is-log: false
|
使用 Sa-Token
登录认证
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| @RestController @RequestMapping("/user/") public class UserController {
@PostMapping("login") public SaResult doLogin(@RequestBody LoginVo loginVo) { if ("admin".equals(loginVo.getUsername()) && "123456".equals(loginVo.getPassword())) { StpUtil.login(10001); return SaResult.ok("登录成功").setData(StpUtil.getTokenInfo()); } return SaResult.error("登录失败"); }
@GetMapping("isLogin") public SaResult isLogin() { return SaResult.ok("是否登录:" + StpUtil.isLogin()); }
@GetMapping("tokenInfo") public SaResult tokenInfo() { return SaResult.ok("token信息").setData(StpUtil.getTokenInfo()); }
@PostMapping("logout") public SaResult logout() { StpUtil.logout(); return SaResult.ok("退出成功"); } }
|
权限认证
1. 注解方式鉴权
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| @RestController @RequestMapping("/article/") public class ArticleController {
@SaCheckLogin @GetMapping("info") public SaResult info() { return SaResult.ok("查询文章信息"); }
@SaCheckPermission("user-create") @PostMapping("create") public SaResult create() { return SaResult.ok("创建文章"); }
@SaCheckRole("admin") @DeleteMapping("delete") public SaResult delete() { return SaResult.ok("删除文章"); }
@SaCheckPermission({"user-create", "user-update"}) @PutMapping("update") public SaResult update() { return SaResult.ok("修改文章"); } }
|
2. 代码方式鉴权
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| @RestController @RequestMapping("/goods/") public class GoodsController {
@GetMapping("info") public SaResult info() { Object loginId = StpUtil.getLoginId(); boolean isLogin = StpUtil.isLogin(); StpUtil.checkLogin(); List<String> permissionList = StpUtil.getPermissionList(); List<String> roleList = StpUtil.getRoleList(); boolean hasPermission = StpUtil.hasPermission("user-create"); boolean hasRole = StpUtil.hasRole("admin"); return SaResult.ok("商品信息"); } }
|
会话管理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| @RestController @RequestMapping("/admin/") public class AdminController {
@GetMapping("onlineUser") public SaResult onlineUser() { List<String> tokenList = StpUtil.searchTokenValue("", 0, -1, false); return SaResult.ok("在线用户").setData(tokenList); }
@GetMapping("kickout/{userId}") public SaResult kickout(@PathVariable Long userId) { StpUtil.kickout(userId); return SaResult.ok("强制下线成功"); }
@GetMapping("disable/{userId}") public SaResult disable(@PathVariable Long userId) { StpUtil.disable(userId, 3600); return SaResult.ok("账号封禁成功"); }
@GetMapping("untieDisable/{userId}") public SaResult untieDisable(@PathVariable Long userId) { StpUtil.untieDisable(userId); return SaResult.ok("账号解封成功"); } }
|
集成 Redis
为了实现分布式会话,我们需要集成 Redis:
添加 Redis 依赖
1 2 3 4 5 6 7 8 9 10 11 12
| <dependency> <groupId>cn.dev33</groupId> <artifactId>sa-token-redis</artifactId> <version>1.38.0</version> </dependency>
<dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> </dependency>
|
Redis 配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| spring: redis: database: 0 host: 127.0.0.1 port: 6379 password: lettuce: pool: max-active: 200 max-wait: -1ms max-idle: 10 min-idle: 0
sa-token: token-name: satoken timeout: 2592000 activity-timeout: -1 is-concurrent: true is-share: true token-style: uuid is-log: false is-read-cookie: true
|
微服务集成
在微服务架构中,我们可以通过以下方式集成 Sa-Token:
网关统一鉴权
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| @Component public class AuthGlobalFilter implements GlobalFilter { @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { String path = exchange.getRequest().getURI().getPath(); if (path.contains("/login") || path.contains("/register")) { return chain.filter(exchange); } String token = exchange.getRequest().getHeaders().getFirst("Authorization"); if (token == null) { token = exchange.getRequest().getQueryParams().getFirst("satoken"); } try { StpUtil.checkLogin(token); } catch (Exception e) { ServerHttpResponse response = exchange.getResponse(); response.setStatusCode(HttpStatus.UNAUTHORIZED); String data = JSON.toJSONString(SaResult.error("未登录")); DataBuffer buffer = response.bufferFactory().wrap(data.getBytes(StandardCharsets.UTF_8)); response.getHeaders().add("Content-Type", "application/json;charset=UTF-8"); return response.writeWith(Mono.just(buffer)); } return chain.filter(exchange); } }
|
结语
Sa-Token 是一个功能强大且易于使用的 Java 权限认证框架,它提供了登录认证、权限认证、会话管理、单点登录、OAuth2.0 等一系列权限相关功能。通过简单的配置和注解,开发者可以快速实现复杂的权限控制需求。
无论是在单体应用还是微服务架构中,Sa-Token 都能提供完善的权限认证解决方案,大大简化了权限控制的开发工作。