Sa-Token 集成 Spring Boot 完整指南
1.3k
类别: 
开发交流

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 官方文档

标签:
评论 0
/ 1000
0
0
收藏