一篇搞定!SpringBoot 搭建超安全 Sa-Token 登录鉴权系统

在现代 Java Web 项目中,登录认证与权限管理是不可或缺的基础功能。传统的框架如 Spring Security 和 Shiro 生态成熟,但初学者和中小项目开发者常常觉得配置繁琐、学习成本高。

Sa-Token 的出现正好填补了这一空白:它是一款轻量级 Java 权限认证框架,既能满足登录认证、权限校验、单点登录(SSO)、OAuth2.0、分布式 Session 和微服务网关鉴权等需求,又极大降低了上手门槛。本文将带你从零开始,在 Spring Boot 环境下快速搭建一个完整的登录鉴权系统,并详细讲解原理和最佳实践。

官网地址:https://sa-token.cc/

Sa-Token 是什么?

Sa-Token 是一个轻量级、功能全面的 Java 权限框架,核心功能包括:

  • 登录认证(单账号或多账号体系)

  • 权限校验(角色权限、功能权限)

  • 单点登录(SSO)

  • OAuth2.0 授权

  • 分布式 Session 管理

  • 微服务网关鉴权

简单来说,Sa-Token 能解决大多数项目中遇到的权限相关问题,功能齐全且易上手,是国内很多互联网公司正在使用的技术。

为什么选择 Sa-Token?

相比 Shiro、Spring Security,Sa-Token 有几个显著优势:

  1. 文档友好 官方文档全中文,内容详尽,查阅和理解门槛低。

  2. 生态稳定 虽然是新晋框架,但在国内开源社区已经形成完整生态,曾多次位列 Gitee 最受欢迎开源项目。

  3. 极简易用 使用 Sa-Token,仅需几行代码即可实现完整登录鉴权功能,而同样功能使用 Spring Security 可能需要上百行配置。

总结:如果你希望快速搭建安全、功能完善的权限系统,同时避免繁琐配置,Sa-Token 是一个非常理想的选择。

Spring Boot 集成 Sa-Token

引入依赖

以 Spring Boot 2.7.3 为例:

<!-- pom.xml --><dependency>    <groupId>cn.dev33</groupId>    <artifactId>sa-token-spring-boot-starter</artifactId>    <version>1.36.0</version></dependency>

如果是 Spring Boot 3.x,只需将依赖改为:

 
<artifactId>sa-token-spring-boot3-starter</artifactId>

配置文件(application.yml)

Sa-Token 提供默认配置,可选自定义:​​​​​​​

sa-token:  token-name: sa-token   # Cookie 名称  token-style: uuid      # Token 风格,可选 uuid|simple-uuid|random-32|random-64|random-128|tik

主启动类示例​​​​​​​

package com.icoderoad.satoken;
import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import cn.dev33.satoken.stp.SaManager;
@SpringBootApplicationpublic class SaTokenApplication {    public static void main(String[] args) {        SpringApplication.run(SaTokenApplication.class, args);
        // 打印 Sa-Token 配置信息        System.out.println(SaManager.getConfig());    }}

如果没有自定义配置,SaManager.getConfig() 将打印默认配置。

编写测试 Controller​​​​​​​

package com.icoderoad.satoken.controller;
import org.springframework.web.bind.annotation.*;import cn.dev33.satoken.stp.StpUtil;
@RestController@RequestMapping("/auth")public class AuthController {
    // 登录接口(测试用,用户名密码写死)    @PostMapping("/login")    public String doLogin(@RequestParam String username, @RequestParam String password) {        if("admin".equals(username) && "123456".equals(password)) {            StpUtil.login(10001); // 登录用户,唯一 ID 10001            return "登录成功";        }        return "用户名或密码错误";    }
    // 判断登录状态    @GetMapping("/isLogin")    public boolean isLogin() {        return StpUtil.isLogin();    }
    // 注销    @PostMapping("/logout")    public String logout() {        StpUtil.logout();        return "注销成功";    }}

原理解析:StpUtil.login() 内部完成了:

  • 检查账号是否已登录

  • 生成唯一 Token 并创建 Session

  • 记录 Token 活跃时间

  • 通知全局监听器

  • 将 Token 注入 Cookie

浏览器会自动携带 Cookie,后续请求无需手动传递 Token。

权限校验

告诉 Sa-Token 用户权限

实现 StpInterface 接口:​​​​​​​

package com.icoderoad.satoken.config;
import cn.dev33.satoken.stp.StpInterface;import org.springframework.stereotype.Component;import java.util.List;
@Componentpublic class StpInterfaceImpl implements StpInterface {    @Override    public List<String> getPermissionList(Object loginId, String loginType) {        return List.of("user.add","user.update","user.get","user.delete");    }
    @Override    public List<String> getRoleList(Object loginId, String loginType) {        return List.of("admin","manager");    }}

校验权限​​​​​​​

@GetMapping("/user/list")public String getUserList() {    StpUtil.checkPermission("user-list"); // 如果没有权限,会抛出异常    return "用户列表信息";}

添加全局异常处理后,前端报错信息会更友好。

注解鉴权

Sa-Token 提供两种注解鉴权方式:

  1. 基于拦截器:适合 Controller 层,默认关闭,需要手动注册全局拦截器。

  2. 基于 AOP:可应用于任意层,侵入性低,注意 AOP 与拦截器不可同时启用。

示例:​​​​​​​

@SaCheckPermission("user-add")@PostMapping("/user/add")public String addUser() {    return "新增用户成功";}

集成 Redis(分布式环境)

内存存储有两个问题:

  1. 重启后数据丢失

  2. 多实例共享困难

解决方案:使用 Redis 作为 Token 存储。​​​​​​​

spring:  redis:    host: localhost    port: 6379sa-token:  is-read-cookie: true  is-read-header: true

登录后,Sa-Token 会自动将 Token 和 Session 信息写入 Redis,支持集群环境。

前后端分离应用

登录成功后,手动返回 Token 信息:​​​​​​​

@PostMapping("/login")public Map<String,Object> login(@RequestParam String username,@RequestParam String password){    StpUtil.login(10001);    return StpUtil.getTokenInfo();}

前端将 Token 存储在本地,每次请求通过 Header 携带:

  •  
Header: tokenName=tokenValue

Sa-Token 自动解析请求头,完成身份验证。

前后端分离场景下 Token 使用

前后端分离时无法依赖 Cookie,需要手动管理 Token:

  1. 登录成功返回 Token 信息

  2. 前端存储 Token(localStorage 或 Vue/React 状态管理)

  3. 请求接口时将 Token 放入 Header

// login.jsasync function login() {    const username = document.getElementById("username").value;    const password = document.getElementById("password").value;
    const response = await fetch("/auth/login", {        method: "POST",        headers: { "Content-Type": "application/x-www-form-urlencoded" },        body: `username=${username}&password=${password}`    });
    const data = await response.json();    if(data.tokenValue){        localStorage.setItem(data.tokenName, data.tokenValue);        alert("登录成功");    } else {        alert(data.msg);    }}
// 请求接口示例async function getUserList() {    const tokenName = "sa-token";    const tokenValue = localStorage.getItem(tokenName);
    const response = await fetch("/auth/user/list", {        method: "GET",        headers: { [tokenName]: tokenValue }    });
    const text = await response.text();    alert(text);}

前端页面(Thymeleaf + Bootstrap 示例)​​​​​

<!-- templates/login.html --><!DOCTYPE html><html xmlns:th="http://www.thymeleaf.org"><head>    <meta charset="UTF-8">    <title>Sa-Token 登录示例</title>    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css"></head><body class="bg-light"><div class="container mt-5">    <h2 class="mb-4">登录</h2>    <div class="mb-3">        <input type="text" class="form-control" id="username" placeholder="用户名">    </div>    <div class="mb-3">        <input type="password" class="form-control" id="password" placeholder="密码">    </div>    <button class="btn btn-primary" onclick="login()">登录</button>    <button class="btn btn-secondary" onclick="getUserList()">获取用户列表</button></div>
<script>async function login() {    const username = document.getElementById("username").value;    const password = document.getElementById("password").value;
    const params = new URLSearchParams({username, password});    const response = await fetch("/auth/login", {method:"POST", body: params});    const data = await response.json();    if(data.tokenValue){        localStorage.setItem(data.tokenName, data.tokenValue);        alert("登录成功");    } else {        alert(data.msg);    }}
async function getUserList() {    const tokenName = "sa-token";    const tokenValue = localStorage.getItem(tokenName);
    const response = await fetch("/auth/user/list", {        headers: { [tokenName]: tokenValue }    });    const text = await response.text();    alert(text);}</script></body></html>

总结与扩展

通过本文示例,我们完成了:

  • Spring Boot 项目快速集成 Sa-Token

  • 用户登录、注销、状态校验

  • 权限与角色管理

  • 注解鉴权与 API 鉴权

  • Redis 分布式存储支持

  • 前后端分离项目 Token 使用

Sa-Token 还支持记住我、同端互斥、二级认证、账号封禁、单点登录、OAuth2 等功能,接入简单、可扩展性强。相比 Spring Security 和 Shiro,它在国内项目中具有更快的上手体验和灵活性。如果你想快速搭建安全、高效的权限系统,Sa-Token 是一个值得尝试的方案

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐