Sa-Token使用指南
Sa-Token使用指南
1. 基础配置
1.1 添加依赖
<!-- 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-redis</artifactId><version>1.34.0</version>
</dependency>
1.2 配置文件
# Sa-Token配置
sa-token:# token名称token-name: Authorization# token有效期timeout: 2592000# token临时有效期activity-timeout: -1# 是否允许同一账号并发登录is-concurrent: true# 在多人登录同一账号时,是否共用一个tokenis-share: false# token风格token-style: uuid# 是否输出操作日志is-log: false# Redis配置
spring:redis:host: localhostport: 6379password: database: 0
2. 基础使用
2.1 登录认证
@RestController
@RequestMapping("/auth")
public class AuthController {@PostMapping("/login")public Result login(@RequestBody LoginDTO loginDTO) {// 验证用户名密码if("admin".equals(loginDTO.getUsername()) && "123456".equals(loginDTO.getPassword())) {// 登录成功,记录用户idStpUtil.login(10001);return Result.success();}return Result.error("登录失败");}@PostMapping("/logout")public Result logout() {StpUtil.logout();return Result.success();}@GetMapping("/check")public Result check() {// 检查是否登录if(StpUtil.isLogin()) {return Result.success("已登录");}return Result.error("未登录");}
}
2.2 权限认证
@RestController
@RequestMapping("/user")
public class UserController {@SaCheckPermission("user:add")@PostMapping("/add")public Result add() {// 需要user:add权限才能访问return Result.success();}@SaCheckRole("admin")@PostMapping("/delete")public Result delete() {// 需要admin角色才能访问return Result.success();}
}
3. 权限管理
3.1 角色权限配置
@Configuration
public class SaTokenConfig {@Beanpublic StpInterface stpInterface() {return new StpInterface() {@Overridepublic List<String> getPermissionList(Object loginId, String loginType) {// 返回此 loginId 拥有的权限列表List<String> permissionList = new ArrayList<>();if(loginId.equals(10001)) {permissionList.add("user:add");permissionList.add("user:delete");}return permissionList;}@Overridepublic List<String> getRoleList(Object loginId, String loginType) {// 返回此 loginId 拥有的角色列表List<String> roleList = new ArrayList<>();if(loginId.equals(10001)) {roleList.add("admin");}return roleList;}};}
}
3.2 全局异常处理
@RestControllerAdvice
public class GlobalExceptionHandler {@ExceptionHandler(NotLoginException.class)public Result handleNotLoginException(NotLoginException e) {return Result.error("未登录");}@ExceptionHandler(NotPermissionException.class)public Result handleNotPermissionException(NotPermissionException e) {return Result.error("无权限");}@ExceptionHandler(NotRoleException.class)public Result handleNotRoleException(NotRoleException e) {return Result.error("无角色");}
}
4. 高级功能
4.1 记住我功能
@RestController
@RequestMapping("/auth")
public class AuthController {@PostMapping("/login")public Result login(@RequestBody LoginDTO loginDTO) {if("admin".equals(loginDTO.getUsername()) && "123456".equals(loginDTO.getPassword())) {// 登录时指定是否记住我StpUtil.login(10001, loginDTO.isRememberMe());return Result.success();}return Result.error("登录失败");}
}
4.2 会话管理
@RestController
@RequestMapping("/session")
public class SessionController {@GetMapping("/info")public Result getSessionInfo() {// 获取当前会话是否登录boolean isLogin = StpUtil.isLogin();// 获取当前会话账号idObject loginId = StpUtil.getLoginId();// 获取当前会话账号id(指定类型)Integer loginIdAsInt = StpUtil.getLoginIdAsInt();// 获取当前会话的token值String tokenValue = StpUtil.getTokenValue();// 获取当前会话的token信息SaTokenInfo tokenInfo = StpUtil.getTokenInfo();Map<String, Object> info = new HashMap<>();info.put("isLogin", isLogin);info.put("loginId", loginId);info.put("loginIdAsInt", loginIdAsInt);info.put("tokenValue", tokenValue);info.put("tokenInfo", tokenInfo);return Result.success(info);}
}
4.3 踢人下线
@RestController
@RequestMapping("/auth")
public class AuthController {@PostMapping("/kickout")public Result kickout(@RequestParam Long userId) {// 将指定账号踢下线StpUtil.kickout(userId);return Result.success();}@PostMapping("/kickoutAll")public Result kickoutAll() {// 将当前账号踢下线StpUtil.kickout(StpUtil.getLoginIdAsLong());return Result.success();}
}
5. 与Spring Security集成
5.1 配置类
@Configuration
public class SaTokenConfig {@Beanpublic SaTokenContext getSaTokenContext() {return new SaTokenContextForSpring();}
}
5.2 拦截器配置
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {// 注册Sa-Token拦截器registry.addInterceptor(new SaInterceptor(handle -> {// 指定需要拦截的路径SaRouter.match("/**")// 排除登录接口.notMatch("/auth/login")// 检查是否登录.check(r -> StpUtil.checkLogin());})).addPathPatterns("/**");}
}
6. 与Redis集成
6.1 配置类
@Configuration
public class SaTokenConfig {@Beanpublic SaTokenDao getSaTokenDao() {return new SaTokenDaoRedis();}
}
6.2 Redis配置
spring:redis:host: localhostport: 6379password: database: 0# 连接超时时间timeout: 10slettuce:pool:# 连接池最大连接数max-active: 200# 连接池最大阻塞等待时间max-wait: -1ms# 连接池中的最大空闲连接max-idle: 10# 连接池中的最小空闲连接min-idle: 0
7. 实际应用示例
7.1 用户登录注册
@Service
public class UserService {@Autowiredprivate UserMapper userMapper;public void register(UserRegisterDTO dto) {// 检查用户名是否存在if(userMapper.existsByUsername(dto.getUsername())) {throw new BusinessException("用户名已存在");}// 创建用户User user = new User();user.setUsername(dto.getUsername());user.setPassword(encryptPassword(dto.getPassword()));userMapper.insert(user);}public LoginVO login(LoginDTO dto) {// 查询用户User user = userMapper.findByUsername(dto.getUsername());if(user == null) {throw new BusinessException("用户不存在");}// 验证密码if(!user.getPassword().equals(encryptPassword(dto.getPassword()))) {throw new BusinessException("密码错误");}// 登录StpUtil.login(user.getId());// 返回登录信息LoginVO vo = new LoginVO();vo.setToken(StpUtil.getTokenValue());vo.setUserInfo(convertToVO(user));return vo;}
}
7.2 权限控制
@RestController
@RequestMapping("/api")
public class ApiController {@SaCheckPermission("user:view")@GetMapping("/user/info")public Result getUserInfo() {Long userId = StpUtil.getLoginIdAsLong();User user = userService.getById(userId);return Result.success(user);}@SaCheckRole("admin")@PostMapping("/user/delete/{id}")public Result deleteUser(@PathVariable Long id) {userService.deleteById(id);return Result.success();}
}
8. 注意事项
-
安全性考虑
- 使用HTTPS传输
- 设置合理的token有效期
- 定期更换token
- 敏感操作需要二次验证
-
性能优化
- 合理使用Redis缓存
- 避免频繁的权限检查
- 使用token续期机制
-
异常处理
- 统一处理登录异常
- 统一处理权限异常
- 记录关键操作日志
-
最佳实践
- 遵循最小权限原则
- 实现细粒度的权限控制
- 做好会话管理
- 实现单点登录