给 Java 后端项目加登录与单点登录(Sa-Token)

Sa-Token 是 dromara 维护的 Java 权限认证框架,把登录会话、权限与角色校验、踢人下线、SSO、OAuth2.0、微服务网关鉴权等能力收进静态方法调用与注解里。这篇文章梳理它的核心模块定位、最短安装示例、主要功能与关键配置项,说明结果在哪儿看,并整理 GitHub Issue 里用户真实踩过的坑,最后给出两个同类项目的横向对照,帮读者判断自己的项目该不该用它。

给一个 Java 后端项目补上登录,要做的事往往比预期多:会话存哪里、令牌怎么发、接口怎么拦、多端登录要不要互斥、网关那一层怎么统一校验。Sa-Token 是 dromara 组织维护的一套 Java 权限认证框架,把这些分散的决定收进了一组静态方法调用里。

Sa-Token 是用 Java 写的开源权限认证框架,输入账号 id 与请求上下文,输出登录会话与权限判断结果,供 SpringBoot 等后端项目做登录、鉴权与单点登录。

它面向的场景很具体:APP、小程序这类不支持 Cookie 的终端也要鉴权;多台服务器之间要共享会话;同一个系统里 User 表和 Admin 表要分开鉴权;再往外走,还要接 SSO 单点登录、OAuth2.0 授权、微服务网关统一认证。仓库地址 https://github.com/dromara/Sa-Token,采用 Apache-2.0 许可证,主要语言 Java,当前 Star 19073、Fork 2912、开放 Issue 118,最近一次提交在 2026-09-27,默认分支为 dev。

Sa-Token 的 SSO 三种模式与核心模块示意图

它不做什么

README 里专门澄清过一件事:Sa-Token 不是对 Spring Security 的封装,也不是套壳 Apache Shiro。

它的能力边界在 Java 生态内。非 Java 项目想接它的单点登录,走的是 NoSdk 方式,通过 sso-server 的接口对接,不引入 SDK。

持久化不是默认带的。README 把「可集成 Redis,重启数据不丢失」写在持久层扩展这一条里,会话数据要落盘就得自己接 Redis。

商业支持也不提供。文档写明赞助仅为友情赞助,不提供任何商业交换,框架与在线文档承诺永久免费开放。

用之前先准备好什么

环境上,JDK 支持范围是 8 到 25,SpringBoot 2 与 SpringBoot 3/4 都有对应集成包,Solon、JFinal 也在支持列表里。构建工具按 README 是 Maven,依赖坐标写在 pom.xml 中,groupId 固定为 cn.dev33。

要用分布式会话,或者用 SSO 的跨 Redis 模式、前后端不同域的架构,需要先准备可用的 Redis;模式三在前后端不同域、后端也不同 Redis 的情况下使用,还得部署 sso-server。仓库目录里有 sa-token-demo/,SSO 的三种模式各自带可直接运行的示例。

主要功能

登录认证与会话管理。一行 StpUtil.login(10001) 完成会话登录,参数是登录人的账号 id,不需要实现接口或创建配置文件。需要拦截时调用 StpUtil.checkLogin(),未登录会抛 NotLoginException。支持单端登录、多端登录、同端互斥登录与七天免登录,Token 内置六种风格,也可以自定义生成策略。

权限与角色认证。注解方式把鉴权与业务代码分开,方法上写 @SaCheckPermission("user:add"),只有具备该权限的会话才能进入方法。路由拦截方式按模块划分:

registry.addInterceptor(new SaInterceptor(handler -> {
    SaRouter.match("/user/**", r -> StpUtil.checkPermission("user"));
    SaRouter.match("/admin/**", r -> StpUtil.checkPermission("admin"));
})).addPathPatterns("/**");

一个系统里有多套账号体系时,可以按账号类型分开鉴权,比如商城的 User 表和 Admin 表走各自的登录逻辑。

踢人下线与账号封禁。按账号 id 踢下线写 StpUtil.kickout(10077),也能按 Token 值踢。封禁支持登录封禁、按业务分类封禁和按处罚阶梯封禁。

单点登录 SSO。分三种模式:前端同域加后端同 Redis 用模式一,靠共享 Cookie 同步会话;前端不同域加后端同 Redis 用模式二,靠 URL 重定向传播会话;两个都不满足时用模式三托底,走 HTTP 请求校验 ticket 获取会话。校验环节包含域名校验、ticket 校验与参数签名校验。README 提到一个细节:部分同类框架登录后会把带参数的地址截断,Sa-Token 内的算法保证登录后按原地址返回,参数不丢。

OAuth2.0 授权。四种授权模式覆盖不同场景:授权码式是标准流程,server 下放 code、client 兑换 access_token;隐藏式用 URL 重定向把 access_token 直接给到客户端页面;密码式由 client 拿用户账号密码换 access_token;客户端凭证式发放 client 级别的 client_token,代表应用自身的资源授权。

微服务与 RPC 鉴权。网关层适配 Gateway、ShenYu、Zuul 等常见网关的路由拦截认证;dubbo、grpc 有对应集成包,在 RPC 调用时登录状态不丢失。

API Key、参数签名与临时 Token。API Key 模块与 TOTP 在 v1.42.0 新增;参数签名模块用于跨系统 API 调用的签名校验,防参数篡改与请求重放;TempToken 模块经过重构,新增了用 value 反查 token 的机制,用于短时间的授权需求。

安装与最短示例

在 SpringBoot 项目里引一个依赖即可:

<dependency>
    <groupId>cn.dev33</groupId>
    <artifactId>sa-token-spring-boot-starter</artifactId>
    <version>1.46.0</version>
</dependency>

登录与校验各一行静态调用:

// 会话登录,参数填登录人的账号 id
StpUtil.login(10001);

// 校验当前客户端是否已经登录,未登录抛出 NotLoginException
StpUtil.checkLogin();

如果改用 WebFlux 或 Solon,换成对应的 starter 集成包,仓库里为这些框架都提供了集成模块。

关键参数

配置项与接口参数集中在几个地方。allowLoginIdColon 在 v1.46.0 新增,默认禁止 loginId 包含冒号,属于不向下兼容的改动,账号体系里带冒号的要从这里放行。

StpInterface.isDisabled 在 v1.46.0 补充了 loginType 参数,同样不向下兼容;实现该接口做账号禁用判断的代码需要跟着调整。

注销相关参数上,SaLogoutParameter 在 v1.43.0 新增 deviceId,用于控制指定设备 id 的注销。同一账号不允许多客户端同时登录时,v1.45.0 新增的重复登录处理策略可以选择踢人下线或拦截本次登录。自动续期有 active-timeout 这条线,允许在单次请求中跳过续期,避免定时轮询被算作活跃行为。

JSON 序列化上,v1.46.0 针对 Jackson DefaultTyping 的多态反序列化 RCE 增加了 SaJsonStrategy 全局类型白名单,这个属于安全相关配置,升级时不要跳过。

结果在哪里看

控制器只负责业务,鉴权结果以两种方式体现:要么方法正常返回,要么抛出异常,未登录抛 NotLoginException,权限不足时抛对应异常,可以在全局异常处理里统一接管。

会话数据的落点取决于是否接 Redis。不接 Redis 时数据在内存里,README 把「重启数据不丢失」作为集成 Redis 的收益列出;接了 Redis 之后,会话与权限缓存可以从 Redis 里查。仓库另有独立 Redis 的能力,用于把权限缓存与业务缓存分开。

想直接看运行效果,可以跑 sa-token-demo/ 下的示例工程,SSO 三种模式都带了完整可运行的客户端。完整文档在项目官网 sa-token.com。

实际使用中的坑

路由拦截报未能读取到有效 Token。现象是 NestedServletException 里包着 NotLoginException: 未能读取到有效Token,出现版本 1.30,这条 Issue 有 67 条评论,是仓库里讨论最多的一条,当前状态已解决。

SpringBoot 4 适配。SpringBoot 4 正式版发布后有用户提了适配请求,47 条评论,已解决。项目支持列表里明确写着 SpringBoot 2 与 SpringBoot 3/4,用新版本前建议先确认集成包版本。

二次登录导致栈溢出。1.44.0 版本下出现 StackOverflowError,异常从 DispatcherServlet 抛出,16 条评论,已解决。

WebFlux 与网关下拿不到上下文。1.34.0 配 SpringBoot 3.0.1、JDK 17 时概率性抛 InvalidContextException: 未能获取有效的上下文;另一条 1.38.0 的 gateway 场景同类报错共 11 条评论,状态是待解决,用 WebClient 构造请求的写法尤其要注意。template

跨域配置改动后 token 失效。1.43.0 下解决跨域问题之后反而出现 未能读取到有效 token,13 条评论,已解决。CORS 相关的处理函数在 v1.42.0 之后有单独模块,改动跨域策略时值得对照文档检查一遍。

横向对照

下面三个项目按仓库自述都归在身份认证与单点登录这一类里,横向位置供选型参考。

项目适合谁部署方式主要限制什么情况下选它更合适项目地址
dromara/Sa-Token用 SpringBoot、WebFlux、Solon 做后端,希望登录、权限、SSO、网关鉴权一次配齐的 Java 团队Maven 引依赖,按需自行接入 Redis;SSO 模式三要自建 sso-server会话持久化要自己接 Redis;社区交流以中文为主;v1.46.0 含两处不向下兼容改动鉴权逻辑要嵌在业务应用里,且需要注解与路由两种拦截方式同时可用时dromara/Sa-Token
apereo/cas想把身份认证做成独立服务对外提供单点登录的团队,仓库自述为 Identity & Single Sign On仓库没有说明未逐一核实鉴权要从业务应用里彻底剥离,作为独立身份服务存在时,这个方向更贴近apereo/cas
pac4j/pac4j需要在多个 Java Web 框架之间复用同一套认证与授权逻辑的团队,仓库自述为 Java 的安全引擎仓库没有说明未逐一核实项目里框架选型不统一、希望认证层与具体框架解耦时,可以看它pac4j/pac4j

如果团队要做的是跨语言、跨组织的统一身份服务,把认证逻辑嵌进每个后端应用的方案就不合适,apereo/cas 这类以独立身份中心为定位的项目更贴近这种需求。Sa-Token 的中文文档与中文社区对国内团队是省事的地方,反过来也意味着团队里没有中文成员时,可选的求助渠道更少。它更擅长的是单个 Java 应用内部的登录与权限,而不是替代一整套企业级身份基础设施。

适合谁

正在写 SpringBoot 或 WebFlux 后端、要在业务代码里快速加上登录与权限校验的 Java 开发者,用 Sa-Token 省事:引一个依赖,登录与校验各一行,权限可以走注解也可以走路由匹配。

有多套账号体系、要做同端互斥登录、要把会话放到 Redis 做分布式的项目,也能在这里找到对应模块;需要单点登录或 OAuth2.0 时,仓库提供了具体模式和可运行示例。

非 Java 技术栈的团队不适合把 Sa-Token 当主力鉴权方案,它的集成包都围绕 Java 生态,非 Java 项目只能走 NoSdk 方式对接 SSO。需要独立部署身份中心、跨组织对接标准化认证协议的场景,也应该去看 apereo/cas 这类以身份服务为定位的项目。已经在用 Spring Security 且团队对它很熟、现有配置也不复杂的项目,迁移过来收益有限。

焚评:这个项目的量化评分

本项目的选题来自 焚.com(一个按公开公式给 GitHub 项目打分的站)。焚评当前总分 9.7 分(满分 10)。下表是各维度的得分:

评分维度得分
热度动量(权重 25%)10.0 / 10
开发活跃(权重 25%)9.3 / 10
社区响应(权重 15%)9.8 / 10
文档质量(权重 15%)10.0 / 10
发布节奏(权重 10%)8.8 / 10
风险控制(权重 10%)10.0 / 10

评分口径、权重与计算方式见焚.com 的评分方法页;数据随 GitHub 指标刷新,具体数值以焚.com 当前页面为准。本文正文为诀.com 独立撰写,评分数据由焚.com 授权引用。

内容核验说明

这篇的价值在于把 Sa-Token 的安装、关键配置项和升级风险放在一处,尤其点出 v1.46.0 两处不向下兼容改动、Jackson 反序列化白名单这类容易漏掉的安全配置,再整理了 GitHub Issue 里高频的几类报错,末尾给了与 CAS、pac4j 的横向定位。

文中 Star 19073、Fork 2912、开放 Issue 118、最近提交时间等仓库指标来自 GitHub 公开数据抓取(2026-10-13),焚评分值引自焚.com,诀.com 未独立验证。各类报错现象、版本号与评论数来自 GitHub Issue 提交者的公开描述,属用户报告,本站未复现,结果不保证可复现。安装示例、配置项与功能说明来自项目 README 与在线文档,亦未逐一实测。

项目来源与说明

开源项目:dromara(dromara)

本文由诀.com 编辑基于该项目的公开信息独立撰写,属原创解读,不是对项目文档的翻译或转载;文中提到的功能与参数以官方仓库为准,代码与文档版权归原作者所有。

查看项目仓库