Sa-Token 集成 Spring Boot 完整指南
Sa-Token 集成 Spring Boot 完整指南
1. 什么是 Sa-Token
Sa-Token 是一个轻量级 Java 权限认证框架,主要解决:登录认证、权限认证、Session会话、单点登录、OAuth2.0 等一系列权限相关问题。
2. 环境准备
2.1 创建 Spring Boot 项目
使用 Spring Initializr 创建项目,选择以下依赖:
- Spring Web
- Lombok(可选)
2.2 添加 Sa-Token 依赖
<!-- pom.xml -->
<dependencies>
<!-- Spring Boot Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Sa-Token 权限认证 -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-spring-boot-starter</artifactId>
<version>1.34.0</version>
</dependency>
<!-- Sa-Token 整合 Redis -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-dao-redis</artifactId>
<version>1.34.0</version>
</dependency>
<!-- Redis 连接池 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
3. 基础配置
3.1 配置文件
# application.yml
server:
port: 8080
spring:
# Redis 配置
redis:
host: 127.0.0.1
port: 6379
password:
database: 0
lettuce:
pool:
max-active: 8
max-wait: -1ms
max-idle: 8
min-idle: 0
# Sa-Token 配置
sa-token:
# token 名称(也是 cookie 名称)
token-name: satoken
# token 有效期(单位:秒)默认30天,-1 代表永不过期
timeout: 2592000
# token 临时有效期(指定时间内无操作就视为 token 过期)单位:秒
activity-timeout: -1
# 是否允许同一账号并发登录(为 true 时允许一起登录,为 false 时新登录挤掉旧登录)
is-concurrent: true
# 在多人登录同一账号时,是否共用一个 token(为 true 时所有登录共用一个 token,为 false 时每次登录新建一个 token)
is-share: true
# token 风格
token-style: uuid
# 是否输出操作日志
is-log: true
3.2 配置类
@Configuration
public class SaTokenConfigure implements WebMvcConfigurer {
/**
* 注册 Sa-Token 的注解拦截器,打开注解式鉴权功能
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 注册注解拦截器,并排除不需要注解鉴权的接口地址(与登录拦截器无关)
registry.addInterceptor(new SaInterceptor()).addPathPatterns("/**");
}
}
4. 登录认证实现
4.1 用户服务类
@Service
public class UserService {
/**
* 模拟用户查询
*/
public User findUserByName(String username) {
// 这里应该是数据库查询,这里简单模拟
if ("admin".equals(username)) {
return new User(1L, "admin", "123456", Arrays.asList("admin", "user"));
} else if ("user".equals(username)) {
return new User(2L, "user", "123456", Arrays.asList("user"));
}
return null;
}
/**
* 用户实体类
*/
@Data
@AllArgsConstructor
public static class User {
private Long id;
private String username;
private String password;
private List<String> roles;
}
}
4.2 登录控制器
@RestController
@RequestMapping("/auth")
public class AuthController {
@Autowired
private UserService userService;
/**
* 用户登录
*/
@PostMapping("/login")
public SaResult login(@RequestParam String username, @RequestParam String password) {
// 1. 查询用户
UserService.User user = userService.findUserByName(username);
if (user == null) {
return SaResult.error("用户不存在");
}
// 2. 验证密码(实际项目中密码应该加密存储)
if (!user.getPassword().equals(password)) {
return SaResult.error("密码错误");
}
// 3. 登录并设置权限
StpUtil.login(user.getId());
// 4. 设置角色和权限
StpUtil.getSession().set("user", user);
for (String role : user.getRoles()) {
StpUtil.getRoleList().add(role);
}
return SaResult.ok("登录成功").setData(StpUtil.getTokenInfo());
}
/**
* 用户注销
*/
@PostMapping("/logout")
public SaResult logout() {
StpUtil.logout();
return SaResult.ok("注销成功");
}
/**
* 查询登录状态
*/
@GetMapping("/isLogin")
public SaResult isLogin() {
return SaResult.ok("是否登录:" + StpUtil.isLogin())
.setData("loginId:" + StpUtil.getLoginIdDefaultNull());
}
}
5. 权限校验
5.1 注解式权限校验
@RestController
@RequestMapping("/user")
public class UserController {
/**
* 查询用户信息(需要登录)
*/
@SaCheckLogin
@GetMapping("/info")
public SaResult info() {
UserService.User user = (UserService.User) StpUtil.getSession().get("user");
return SaResult.data(user);
}
/**
* 添加用户(需要 admin 角色)
*/
@SaCheckRole("admin")
@PostMapping("/add")
public SaResult addUser() {
return SaResult.ok("添加用户成功");
}
/**
* 删除用户(需要 admin 角色 或 user:delete 权限)
*/
@SaCheckPermission(value = {"user:delete"}, orRole = "admin")
@DeleteMapping("/delete/{id}")
public SaResult deleteUser(@PathVariable Long id) {
return SaResult.ok("删除用户成功: " + id);
}
/**
* 修改用户(需要登录且拥有 user:update 权限)
*/
@SaCheckPermission("user:update")
@PutMapping("/update")
public SaResult updateUser() {
return SaResult.ok("修改用户成功");
}
}
5.2 编程式权限校验
@RestController
@RequestMapping("/order")
public class OrderController {
/**
* 创建订单
*/
@PostMapping("/create")
public SaResult createOrder() {
// 编程式校验是否登录
if (!StpUtil.isLogin()) {
return SaResult.error("请先登录");
}
// 编程式校验角色
if (!StpUtil.hasRole("user")) {
return SaResult.error("没有用户权限");
}
// 编程式校验权限
if (!StpUtil.hasPermission("order:create")) {
return SaResult.error("没有创建订单的权限");
}
return SaResult.ok("创建订单成功");
}
}
6. 全局异常处理
@RestControllerAdvice
public class GlobalExceptionHandler {
/**
* 拦截所有 Sa-Token 相关异常
*/
@ExceptionHandler(SaTokenException.class)
public SaResult handlerSaTokenException(SaTokenException e) {
return SaResult.error(e.getMessage());
}
/**
* 拦截所有其他异常
*/
@ExceptionHandler(Exception.class)
public SaResult handlerException(Exception e) {
e.printStackTrace();
return SaResult.error("系统异常:" + e.getMessage());
}
}
7. 路由拦截器
@Component
public class RouteInterceptor extends SaRouteInterceptor {
/**
* 自定义路由拦截器
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
// 登录认证 -- 拦截所有路由,并排除 /auth/login 用于开放登录
SaRouter.match("/**")
.notMatch("/auth/login")
.check(r -> StpUtil.checkLogin());
// 角色认证 -- 拦截以 admin 开头的路由,必须具有 admin 角色才能通过
SaRouter.match("/admin/**").check(r -> StpUtil.checkRole("admin"));
// 权限认证 -- 不同模块校验不同权限
SaRouter.match("/user/**").check(r -> StpUtil.checkPermission("user"));
SaRouter.match("/order/**").check(r -> StpUtil.checkPermission("order"));
return true;
}
}
8. Session 管理
@RestController
@RequestMapping("/session")
public class SessionController {
/**
* 获取当前 Session 信息
*/
@GetMapping("/info")
public SaResult sessionInfo() {
return SaResult.data(StpUtil.getSession());
}
/**
* 设置 Session 值
*/
@PostMapping("/set")
public SaResult setSession(@RequestParam String key, @RequestParam String value) {
StpUtil.getSession().set(key, value);
return SaResult.ok("设置成功");
}
/**
* 获取 Session 值
*/
@GetMapping("/get")
public SaResult getSession(@RequestParam String key) {
return SaResult.data(StpUtil.getSession().get(key));
}
}
9. 测试接口
9.1 测试步骤
启动应用
mvn spring-boot:run
测试登录
curl -X POST http://localhost:8080/auth/login \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "username=admin&password=123456"
携带 Token 访问受保护接口
curl -X GET http://localhost:8080/user/info \
-H "satoken: 上面返回的token值"
10. 高级功能
10.1 踢人下线
@RestController
@RequestMapping("/admin")
public class AdminController {
/**
* 将指定用户踢下线
*/
@PostMapping("/kickout/{loginId}")
public SaResult kickout(@PathVariable Object loginId) {
StpUtil.kickout(loginId);
return SaResult.ok("用户 " + loginId + " 已被踢下线");
}
/**
* 封禁账号
*/
@PostMapping("/disable/{loginId}")
public SaResult disableAccount(@PathVariable Object loginId,
@RequestParam Long time) {
StpUtil.disable(loginId, time);
return SaResult.ok("账号 " + loginId + " 已被封禁 " + time + " 秒");
}
}
10.2 二级认证
@RestController
@RequestMapping("/sensitive")
public class SensitiveController {
/**
* 敏感操作 - 需要二级认证
*/
@SaCheckSafe("user-password")
@PostMapping("/resetPassword")
public SaResult resetPassword() {
return SaResult.ok("密码重置成功");
}
/**
* 开启二级认证
*/
@PostMapping("/openSafe")
public SaResult openSafe(@RequestParam String password) {
StpUtil.openSafe("user-password", 120); // 有效期120秒
return SaResult.ok("二级认证已开启");
}
}
总结
通过以上步骤,我们成功集成了 Sa-Token 到 Spring Boot 项目中,实现了:
✅ 用户登录认证
✅ 角色权限控制
✅ Session 管理
✅ 路由拦截
✅ 全局异常处理
✅ Redis 会话存储
✅ 高级安全功能
Sa-Token 设计简洁、功能强大,是 Spring Boot 项目中权限管理的优秀解决方案。更多高级功能请参考Sa-Token 官方文档。