SpringBoot Sa-Token权限认证实战:微服务极简鉴权方案与集成教程

在 Java 后端开发中,权限认证是绕不开的话题——登录校验、角色权限控制、接口防刷、分布式会话共享等需求,传统方案(如 Shiro、Spring Security)配置繁琐、上手成本高。而 Sa-Token 作为一款轻量级权限认证框架,以“API 简洁、零侵入、易扩展”为核心优势,完美适配 SpringBoot 单体应用与微服务架构,让权限开发效率翻倍。本文就从实际使用场景出发,手把手教你玩转 Sa-Token 的整合与落地。
一、先搞懂:Sa-Token 到底是什么?
Sa-Token 不是复杂的框架,而是一套“开箱即用”的权限工具包,核心解决「认证」与「授权」两大问题。它支持用户名密码登录、短信验证码登录、OAuth2.0、JWT、角色权限控制、会话管理等几乎所有权限场景,最大特点是:API 设计极简,无需复杂配置,新手也能快速上手。对比传统框架,Sa-Token 的优势的很明显:
- 零侵入集成:与 SpringBoot、SpringCloud 无缝衔接,无需修改原有业务代码,引入依赖即可用;
- API 够直观:登录用 StpUtil.login(id),校验登录用 StpUtil.checkLogin(),权限校验用@SaCheckRole(“admin”),一眼就能懂;
- 分布式友好:原生支持 Redis、MongoDB 等存储,轻松解决微服务跨节点会话共享问题;
- 功能全覆盖:从基础的登录态管理,到复杂的权限注解、接口限流、踢人下线,满足全场景需求。
二、实战 1:Sa-Token 整合 SpringBoot 单体应用
单体应用是最常见的场景,整合步骤仅需 3 步,全程不超过 5 分钟。
1.1 引入依赖
在 SpringBoot 项目的 pom.xml 中引入 Sa-Token 依赖(Maven 示例,Gradle 可对应调整):
<!-- Sa-Token 核心依赖 --> <dependency> <groupId>cn.dev33</groupId> <artifactId>sa-token-spring-boot-starter</artifactId> <version>1.38.0</version> <!-- 版本建议用最新稳定版 --> </dependency><!-- 可选:如需使用 Redis 存储会话(推荐),引入此依赖 --> <dependency> <groupId>cn.dev33</groupId> <artifactId>sa-token-redis-jackson</artifactId> <version>1.38.0</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
1.2 核心配置
在 application.yml 中添加配置,指定会话存储方式、Token 有效期等核心参数(按需配置,非必填项有默认值):
spring: redis: host: localhost port: 6379 password: 123456 sa-token: token-name: satoken timeout: 2592000 store-type: redis is-concurrent: true is-share: false
1.3 业务代码整合
配置完成后,直接在业务逻辑中调用 Sa-Token API 即可,无需额外编写拦截器、过滤器。
1.3.1 登录功能实现
用户登录时,调用 StpUtil.login()即可完成会话创建,Sa-Token 会自动生成 Token 并存储:
@RestController
@RequestMapping("/user")
public class UserController {
// 模拟数据库查询(实际项目替换为 MyBatis/Redis 查询)
private User getByUsernameAndPwd(String username, String password) {
if ("admin".equals(username) && "123456".equals(password)) {
User user = new User();
user.setId(1L);
user.setUsername("admin");
user.setRole("admin"); // 角色标识
return user;
}
return null;
}
// 登录接口
@PostMapping("/login")
public SaResult login(String username, String password) {
// 1. 校验用户名密码
User user = getByUsernameAndPwd(username, password);
if (user == null) {
return SaResult.error("用户名或密码错误");
}
// 2. 登录:将用户 ID 存入会话
StpUtil.login(user.getId());
// 3. 获取生成的 Token 返回给前端
String token = StpUtil.getTokenValue();
return SaResult.ok("登录成功").set("token", token).set("user", user);
}
// 退出登录接口
@PostMapping("/logout")
public SaResult logout() {
StpUtil.logout(); // 清除当前会话
return SaResult.ok("退出成功");
}
}
1.3.2 权限校验实现
通过注解或 API 两种方式实现权限控制,注解方式更简洁,适合接口层校验。
@RestController
@RequestMapping("/admin")
public class AdminController {
// 注解方式:仅允许拥有 admin 角色的用户访问
@SaCheckRole("admin")
@GetMapping("/dashboard")
public SaResult adminDashboard() {
// 获取当前登录用户 ID
Long userId = StpUtil.getLoginIdAsLong();
return SaResult.ok("管理员控制台").set("userId", userId);
}
// 注解方式:同时满足多个角色(or 逻辑用@SaCheckRoles)
@SaCheckRole({"admin", "super"})
@PostMapping("/update")
public SaResult updateSystem() {
return SaResult.ok("系统配置更新成功");
}
// API 方式:手动校验权限(适合复杂业务逻辑中校验)
@GetMapping("/user/list")
public SaResult getUserList() {
// 手动校验是否登录
if (!StpUtil.isLogin()) {
return SaResult.error("请先登录");
}
// 手动校验是否拥有 admin 角色
if (!StpUtil.hasRole("admin")) {
return SaResult.error("无权限访问");
}
// 业务逻辑...
return SaResult.ok("用户列表").set("data", new ArrayList<>());
}
}
1.3.3 全局异常处理
当权限校验失败时,Sa-Token 会抛出对应的异常,我们可以统一捕获并返回友好提示:
@RestControllerAdvice
public class GlobalExceptionHandler {
// 捕获 Sa-Token 相关异常
@ExceptionHandler(SaTokenException.class)
public SaResult handleSaTokenException(SaTokenException e) {
return SaResult.error(e.getMessage()).set("code", 401);
}
// 其他全局异常...
}
三、实战 2:Sa-Token 适配微服务架构
微服务的核心问题是「分布式会话共享」和「跨服务权限校验」,Sa-Token 结合 SpringCloud,通过 Redis 统一存储会话,配合网关拦截,轻松解决这些问题。先明确微服务架构核心组件:网关(Gateway)+多个业务服务+ Redis,整体流程:前端请求先经过网关,网关校验 Token 有效性,通过后转发到对应业务服务,业务服务可直接获取登录信息无需二次校验。
3.1 微服务整体配置
所有服务(网关+业务服务)都需引入 Sa-Token 依赖和 Redis 依赖,且 application.yml 中 sa-token.store-type 统一设为 redis,Redis 配置保持一致(指向同一个 Redis 实例)。这样所有服务都能从 Redis 中读取会话信息,实现跨节点会话共享。
3.2 网关层统一拦截校验
在 SpringCloud Gateway 中配置 Sa-Token 拦截器,统一校验 Token,避免每个业务服务重复校验。
@Configuration
public class SaTokenGatewayConfig {
@Bean
public SaTokenGatewayFilter saTokenGatewayFilter() {
return new SaTokenGatewayFilter()
// 配置不需要拦截的路径(白名单)
.addExcludePath("/user/login")
.addExcludePath("/user/register")
// 配置需要拦截的路径(黑名单),也可省略,默认拦截所有非白名单路径
.addIncludePath("/**");
}
// 将拦截器注入网关过滤器链
@Bean
public RouteLocator routeLocator(RouteLocatorBuilder builder) {
return builder.routes()
// 业务服务 1:用户服务
.route("user-service", r -> r.path("/user/**")
.uri("lb://user-service"))
// 业务服务 2:管理员服务
.route("admin-service", r -> r.path("/admin/**")
.uri("lb://admin-service"))
.build();
}
}
配置完成后,所有请求都会先经过网关的 Sa-Token 拦截器:未登录、Token 过期、权限不足的请求会直接被拦截并返回提示,只有通过校验的请求才会转发到对应业务服务。
3.3 业务服务获取登录信息
经过网关校验后,业务服务无需再校验 Token,可直接通过 Sa-Token API 获取当前登录用户信息,与单体应用用法完全一致:
// 订单服务(微服务节点)
@RestController
@RequestMapping("/order")
public class OrderController {
@GetMapping("/my")
public SaResult myOrder() {
// 直接获取登录用户 ID(从 Redis 中读取,无需额外处理)
Long userId = StpUtil.getLoginIdAsLong();
// 业务逻辑:查询当前用户的订单
List<Order> orderList = getOrderByUserId(userId);
return SaResult.ok("我的订单").set("data", orderList);
}
// 权限校验依然可用注解
@SaCheckRole("admin")
@GetMapping("/all")
public SaResult allOrder() {
return SaResult.ok("所有订单列表").set("data", new ArrayList<>());
}
}
3.4 微服务进阶:跨服务权限传递
如果存在服务间调用(如订单服务调用用户服务),需要将当前登录用户的 Token 传递给被调用服务。只需在调用时将 Token 放入请求头,被调用服务即可自动识别。
// 订单服务调用用户服务(使用 RestTemplate 示例)
@Service
public class OrderService {
@Autowired
private RestTemplate restTemplate;
public User getUserById(Long userId) {
// 1. 获取当前登录用户的 Token
String token = StpUtil.getTokenValue();
// 2. 将 Token 放入请求头
HttpHeaders headers = new HttpHeaders();
headers.set("satoken", token); // satoken 为配置的 token-name
HttpEntity<?> entity = new HttpEntity<>(headers);
// 3. 调用用户服务接口
ResponseEntity<SaResult> response = restTemplate.exchange(
"http://user-service/user/info/" + userId,
HttpMethod.GET,
entity,
SaResult.class
);
// 4. 处理返回结果
SaResult result = response.getBody();
if (result.getCode() == 200) {
return (User) result.get("data");
}
return null;
}
}
四、实用技巧:让 Sa-Token 更贴合业务
4.1 自定义 Token 生成策略
默认 Token 为 UUID 格式,如需自定义(如 JWT 格式、包含特定信息),可实现 TokenGenerator 接口:
@Component
public class CustomTokenGenerator implements TokenGenerator {
@Override
public String generate(Object loginId, String loginType) {
// 自定义 Token 生成逻辑,示例:JWT 格式
String jwtToken = Jwts.builder()
.setSubject(loginId.toString())
.setExpiration(new Date(System.currentTimeMillis() + 2592000000L))
.signWith(SignatureAlgorithm.HS256, "secretKey")
.compact();
return jwtToken;
}
}
4.2 多端登录隔离
如需区分 PC 端、移动端登录(如 PC 端踢下线不影响移动端),可通过 loginType 实现:
// PC 端登录 StpUtil.login(userId, "PC"); // 移动端登录 StpUtil.login(userId, "APP"); // 仅踢下线 PC 端会话 StpUtil.logoutByLoginId(userId, "PC"); // 获取 PC 端 Token String pcToken = StpUtil.getTokenValueByLoginId(userId, "PC");
4.3 接口限流
Sa-Token 自带接口限流功能,通过注解即可限制接口访问频率:
// 限制同一 IP 每分钟最多访问 10 次
@SaCheckSafe(prefix = "api_limit", value = "user_login", period = 60, count = 10)
@PostMapping("/user/login")
public SaResult login(String username, String password) {
// 业务逻辑...
}
五、总结
Sa-Token 的核心优势在于“简单高效”——无论是 SpringBoot 单体应用,还是 SpringCloud 微服务,都能以极低的成本整合,无需关注底层实现,专注业务逻辑即可。其 API 设计贴近开发者习惯,注解化、零侵入的特性,让权限开发从“繁琐配置”变成“拿来就用”。实际项目中,可根据需求灵活扩展:单体应用用本地内存/Redis 存储,微服用 Redis 统一存储,复杂权限场景可结合 RBAC 模型扩展角色、资源权限。希望本文能帮你快速掌握 Sa-Token 的使用,让权限认证不再成为开发痛点。
以上关于SpringBoot Sa-Token权限认证实战:微服务极简鉴权方案与集成教程的文章就介绍到这了,更多相关内容请搜索码云笔记以前的文章或继续浏览下面的相关文章,希望大家以后多多支持码云笔记。
如若内容造成侵权/违法违规/事实不符,请将相关资料发送至 admin@mybj123.com 进行投诉反馈,一经查实,立即处理!
重要:如软件存在付费、会员、充值等,均属软件开发者或所属公司行为,与本站无关,网友需自行判断
码云笔记 » SpringBoot Sa-Token权限认证实战:微服务极简鉴权方案与集成教程
微信
支付宝