Sa-Token使用指南

发布于:2025-04-19 ⋅ 阅读:(86) ⋅ 点赞:(0)

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
  # 在多人登录同一账号时,是否共用一个token
  is-share: false
  # token风格
  token-style: uuid
  # 是否输出操作日志
  is-log: false

# Redis配置
spring:
  redis:
    host: localhost
    port: 6379
    password: 
    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())) {
            // 登录成功,记录用户id
            StpUtil.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 {
    
    @Bean
    public StpInterface stpInterface() {
        return new StpInterface() {
            @Override
            public 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;
            }
            
            @Override
            public 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();
        // 获取当前会话账号id
        Object 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 {
    
    @Bean
    public SaTokenContext getSaTokenContext() {
        return new SaTokenContextForSpring();
    }
}

5.2 拦截器配置

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
    
    @Override
    public 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 {
    
    @Bean
    public SaTokenDao getSaTokenDao() {
        return new SaTokenDaoRedis();
    }
}

6.2 Redis配置

spring:
  redis:
    host: localhost
    port: 6379
    password: 
    database: 0
    # 连接超时时间
    timeout: 10s
    lettuce:
      pool:
        # 连接池最大连接数
        max-active: 200
        # 连接池最大阻塞等待时间
        max-wait: -1ms
        # 连接池中的最大空闲连接
        max-idle: 10
        # 连接池中的最小空闲连接
        min-idle: 0

7. 实际应用示例

7.1 用户登录注册

@Service
public class UserService {
    
    @Autowired
    private 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. 注意事项

  1. 安全性考虑

    • 使用HTTPS传输
    • 设置合理的token有效期
    • 定期更换token
    • 敏感操作需要二次验证
  2. 性能优化

    • 合理使用Redis缓存
    • 避免频繁的权限检查
    • 使用token续期机制
  3. 异常处理

    • 统一处理登录异常
    • 统一处理权限异常
    • 记录关键操作日志
  4. 最佳实践

    • 遵循最小权限原则
    • 实现细粒度的权限控制
    • 做好会话管理
    • 实现单点登录

网站公告

今日签到

点亮在社区的每一天
去签到