从「能用」到「能放心用」——这是 0.2.0 真正想交付的东西。
我们被看见了,也把自己做硬了
如果你在找 Rust 生态里的认证与授权方案,很可能已经刷到过 sa-token-rust。
它是一套轻量、高性能的 Rust 认证授权框架,设计理念对齐 Java 生态中广为人知的 Dromara sa-token,但代码与实现完全独立(MIT OR Apache-2.0)。
最近三件对社区很重要的事:
- 项目被「旋武社区」收录
开放原子开源基金会旗下旋武社区项目页:
https://xuanwu.openatom.org/articles/project/sa-token-rust/

- 被提名 AtomGit「G-Star」孵化项目
G-Star 开源摘星计划 是 AtomGit 面向优质开源项目的全流程扶持(流量、品牌、运营)。入选孵化,仓库会进入官方 G-Star 展台。
项目详情页:https://atomgit.com/sa-tokens/sa-token-rust

- 正式文档站上线(中英双语)
https://sa-tokens.github.io/sa-token-rust/
从快速入门、迁移指南,到 StpUtil、存储、OAuth2、SSO、安全能力,一站查齐。

旋武收录、G-Star 提名,是「被看见」;而 0.2.0 这一版,我们真正想说的是:看见之后,能不能经得起生产环境拷问。
过去一段时间,仓库按 A0→F 一整套重构路线,把 0.1.x 时代「功能堆得很多、边界却偏软」的地方,系统性地改到了更接近生产级框架的形态。本文用「以前 vs 现在」的方式,把变化讲清楚。
一句话定位(0.2 仍然成立,但更硬)
sa-token-rust:登录 / 鉴权 / Session / 权限角色 / 多账号多端 / 事件总线 / JWT / OAuth2 / SSO / WebSocket 鉴权 / 在线用户 / 分布式 Session —— 用同一套 StpUtil + SaTokenState 心智模型,覆盖 Axum、Actix-web、Poem、Rocket、Warp、Salvo、Tide、Gotham、Ntex,以及 Tonic gRPC。
0.1.x 已经把「能力清单」铺得很全;
0.2.0 做的是:把能力清单背后的契约、安全默认值、插件一致性、可迁移文档,一次性做对。
为什么要动大手术:0.1.x 的真实痛点
如果只用一句话概括 0.1.x 的问题:
功能多,但「写存储」「读 Token」「踢人清理」「插件鉴权」「初始化失败」等关键路径,各自为政,容易在生产里踩坑。
更具体一点:
| 痛点 | 0.1.x 常见表现 | 生产风险 |
|---|---|---|
| 存储契约弱 | 序列化散落 serde_json;键名不统一;缺 CAS / scan 等原子能力 |
多实例不一致、滚动升级困难 |
| Manager 过重 | 登录、踢人、权限、在线……挤在「上帝对象」里 | 难测、难改、静默失效 |
| 登录非事务 | 写了一半失败,索引/Token 可能残留 | 幽灵登录、踢不干净 |
| 插件重复 | 多个 *-core 各写一套中间件 |
框架间行为不一致 |
| 门面易 panic | init_manager / 未初始化路径偏硬 |
库代码里崩进程 |
| 安全默认偏松 | OAuth2 密钥明文倾向、SSO 验票偏弱、续期默认偏激进 | 被扫漏洞时很难解释 |
| 文档与代码漂移 | 迁移说明和真实 API 打架 | 升级成本高、社区信任下降 |
0.2.0 不是「再加几个 feature」,而是按 A0 工程化 → A 存储 → B 核心 → C 插件/门面 → D 安全 → E 能力对齐 → F 收口与性能 的顺序,把地基换了一遍。
总览:重构路线图
A0 工程化基线(fmt/clippy/版本/门禁/根 facade)
A1 存储原语升级(scan / CAS / list / get_del …)
A2 可插拔序列化(SaSerializer,默认 JSON,可选 fory)
A3 存储键统一(SaKeys / 账号命名空间)
B1 Manager 拆分 + 登录事务化(Dao / Repo / AuthService)
B2 授权体系收敛(AuthzService / 权限匹配)
B3 请求上下文单轨化(SaTokenContext)
B4 事件系统重构(DispatchMode / 超时)
C1 插件收敛到 plugin-common(删除 *-core)
C2 StpUtil 门面重整(try_* / SaLogic 无注册表)
C3 宏层增强
D1 OAuth2 / SSO 安全加固
D2 分布式化与遗留清理
D3 测试补全与文档迁移
E1 与 Java 能力对齐补齐(Sign / TempToken / Same-Token …)
E2 配置项落地与 Token 读写链路(token_io)
F 收口与性能(Arc 化、分片缓存、旁路清理)- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
下面按大家最关心的点展开对比。
对比一:工程化 —— 从「能编译」到「能发布」
以前(0.1.x)
- 版本号分散,示例与门禁偶发红灯
- 发布链路对质量门禁依赖弱
- 根包「一键引入」体验不完整
现在(0.2.0)
- Workspace 版本统一
0.2.0,内部依赖进[workspace.dependencies] - 发布脚本
scripts/publish_all.sh内置质量门禁:
cargo fmt --check→clippy -D warnings→cargo test --workspace - 根 crate
sa-token-rust作为 facade,方便cargo add - MSRV、docs.rs、resolver 等元数据补齐
对你意味着什么:
开源项目不只是「仓库里有代码」,而是 可持续发布、可复现构建。旋武社区收录的是一个能交付的工程,而不只是一个 README。
对比二:存储层 —— 从「随便 to_string」到「契约 + 可升级」
以前
- 存储读写路径大量硬编码 JSON
- 键名散落各处,多账号隔离靠约定而非统一布局
- 原子能力(CAS、scan、list)不齐或后端不一致
现在
| 能力 | 说明 |
|---|---|
| SaTokenDao | 唯一存储漏斗:键 + 序列化 + TTL |
| SaKeys | 统一键布局与账号命名空间(login_type 隔离) |
| SaSerializer | 可插拔编码;默认 JSON;可选 fory 二进制 + 滚动升级读存量 JSON |
| SaStorage 原语 | scan / get_del / compare_and_swap / list_* 等生产向能力 |
Memory / Redis / Database(PostgreSQL KV)仍可按插件 feature 切换;业务侧应走 Dao,而不是在服务里直接握底层存储。
对你意味着什么:
换 Redis、扩多实例、以后换编码格式,路径是清晰的;不再「每个模块自己发明一种存法」。
文档入口:Storage 指南
对比三:核心架构 —— 从「上帝 Manager」到「分层 + 事务登录」
以前
SaTokenManager职责过重- 登录写入非阶段化,失败易残留
- 踢人 / 顶号 / 最大登录数等边界有已知缺陷风险
- Token 读路径自动续期默认偏激进,可能「每次读都写存储」
现在
请求 / StpUtil
↓
SaTokenManager(薄门面)
↓
AuthService / AuthzService
↓
TokenRepo / SessionRepo / GrantRepo
↓
SaTokenDao → SaStorage- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
关键变化:
- 登录事务化:阶段写入 + 失败逆序补偿,
login:token用 CAS 作为提交点 - 踢人 / 登出模式:清理路径统一,减少幽灵 Token
auto_renew默认改为false:避免每次鉴权都打存储;需要旧行为时显式打开,并可配renew_threshold- 权限 / 角色 走
AuthzService,与登录事务边界清晰
对你意味着什么:
「登录成功」更接近真正的业务事务语义;「踢人失败却还在线」这类诡异问题显著减少。
对比四:插件与框架 —— 从「五套 core」到「一套 common」
以前
- 多个
sa-token-plugin-*-core重复实现状态、拒绝体、扩展写入 - Warp 等个别框架曾绕过统一鉴权流,行为不一致
- Extractor 缺 Token 时的 HTTP 状态码不统一
现在
- 新建
sa-token-plugin-common:SaTokenState/ rejection / snapshot / ext 一处维护 - 删除 各
*-corecrate - 全框架对齐
run_auth_flow:读 Token、写上下文、路径鉴权同一条链路 - Actix / Rocket / Salvo / Gotham / Ntex 仍是 门面 + 版本绑定 feature;Axum / Poem / Warp / Tide / Tonic 一体化插件
对你意味着什么:
换框架时,心智模型不变:还是 SaTokenState + 中间件 / Layer + StpUtil。少学一套「这个框架特供的坑」。
对比五:StpUtil 门面 —— 从「能 panic」到「Result 优先」
以前
init_manager作为主路径,失败易直接崩- 多账号依赖全局注册表(
put_stp_logic) - 默认路径
login_type分裂:权限已跟上下文,踢人/Session 仍可能写死default - TokenBuilder / Token-Session / 按类型封禁等能力不齐
现在
| API / 概念 | 0.2 行为 |
|---|---|
try_init_manager / try_get_manager |
返回 Result;重复初始化 → AlreadyInitialized |
init_manager |
废弃(仍可能 panic,不推荐) |
SaLogic |
廉价 Clone 门面,无进程级注册表;put_stp_logic 为废弃空操作 |
login / login_with_extra |
固定 default 账号体系(不偷偷跟上下文) |
kick_out / disable / Session 等短方法 |
跟当前请求 login_type,否则 default |
TokenBuilder |
支持 nonce / expire_at / expire_at_unix |
Token-Session / kick_out_by_token / disable_with_type |
门面补齐 |
对你意味着什么:
库代码可以优雅处理「未初始化 / 已初始化」;多账号写法变成「拿一个 SaLogic 钉死类型」,而不是维护一张全局表。
对比六:请求上下文与宏 —— 单轨、可预测
以前
- 上下文与宏、中间件之间存在双轨风险
#[sa_ignore]容易被误解成「中间件也放行」
现在
SaTokenContext单轨化:请求级上下文清晰,宏与中间件共用同一套元数据思路PathAuthConfig::exclude:公开路由必须写进排除列表#[sa_ignore]:只跳过宏插入的检查,绝不绕过 Layer / Middleware#[sa_check_login]:走异步强校验(存储仍有效),handler 需async
这是很多线上事故的「根因级」修正:公开路由靠配置声明,而不是靠宏碰运气。
文档入口:路径鉴权
对比七:安全默认值 —— OAuth2 / SSO / Token 读写
OAuth2 / SSO(以前 vs 现在)
| 项 | 以前倾向 | 0.2.0 |
|---|---|---|
| Client Secret | 易明文落库 | Argon2id PHC 哈希存储与校验 |
| 公共客户端 | PKCE 弱或缺失 | 强制 PKCE(S256) |
| Refresh | 轮换与失败回写不严 | 原子 take + 失败回写 |
| OAuth2/SSO 存储 | 进程内 HashMap | Dao 持久化 |
| SSO 验票 | 偏弱 | 真消费票据 + HMAC 请求签名 |
| 统一登出 | 能力有限 | SloNotifier(HTTP 实现按 feature) |
Token 读写链路
统一走核心 token_io:
read_token:按is_read_header/is_read_cookie/is_read_body真实生效token_prefix:可选前缀(如Bearer)is_write_cookie+write_token_cookie:登录写 Cookie 默认关闭、需显式打开
其它安全能力补齐
- 通用 请求签名
RequestSign - 临时令牌 TempToken
- Same-Token 加固(CSPRNG + CAS 刷新)
- 登录 Token 唯一性重试(
max_try_times)
对你意味着什么:
默认值更保守、更可审计;需要旧行为时必须「知情同意」地打开开关。
对比八:事件、性能与收口
事件总线
DispatchMode:Sequential / Concurrent / Detached- Listener 超时可控;未初始化时
event_bus()返回None,不再硬崩
性能与收口
- Config / TokenValue 等关键路径 Arc 化,降低 Clone 成本
- MemoryStorage 分片;GrantCache 分片 + flight 锁
- 清理 Dao 旁路;Refresh 索引走统一 Repo
- 插件读 Token 统一
token_io
这些改动不喧哗,但决定了高并发下「稳不稳、抖不抖」。
对比九:文档与社区交付 —— 从「仓库说明书」到「双语站点」
以前
- 文档分散、中英不对等、与代码偶有矛盾(例如迁移文写「没有 token_prefix」)
- 旋武收录页目前仍主要镜像较早的 README 能力清单(功能全,但尚未体现 0.2 架构叙事)
现在
- VitePress 正式站:https://sa-tokens.github.io/sa-token-rust/
- 中英成对指南(同一文件名、同一信息密度)
- 根目录 MIGRATION_0.2.md 作为破坏性变更单一真相源
- 站点内迁移页:Migrate to 0.2
从 0.1.x 升级的同学,先读迁移指南再改依赖;新同学直接从 快速入门 开始。
一张表:0.1.x → 0.2.0 速查
| 维度 | 0.1.x | 0.2.0 |
|---|---|---|
| 版本 | 分散(如 0.1.18) | 统一 0.2.0 |
| 初始化 | init_manager 主路径 |
try_init_manager / try_build |
| 存储访问 | 服务常直连 SaStorage |
SaTokenDao 收口 |
| 序列化 | 硬编码 JSON | SaSerializer 可插拔 |
| 键布局 | 分散 | SaKeys + 账号命名空间 |
| 登录 | 非事务、易残留 | 阶段写入 + 补偿 |
| 续期 | 默认偏激进 | auto_renew 默认 false |
| 插件状态 | 多个 *-core |
sa-token-plugin-common |
| 多账号 | 全局注册表 | SaLogic 廉价 Clone,无注册表 |
| 公开路由 | 易误解 sa_ignore |
PathAuthConfig::exclude |
| OAuth2 密钥 | 偏明文 | Argon2id + PKCE |
| SSO | 进程内 / 验票弱 | Dao + 真验票 + 签名 |
| Token 读写 | 各插件略异 | 统一 token_io |
| 文档 | 分散、易过时 | 双语 VitePress + MIGRATION |
最小代码体感(0.2 推荐写法)
use sa_token_plugin_axum::*;
use std::sync::Arc;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let state = SaTokenState::builder()
.storage(Arc::new(MemoryStorage::new()))
.timeout(7200)
.build(); // 内部 try_init_manager
// 库代码更推荐:
// let mgr = SaTokenConfig::builder()
// .storage(Arc::new(MemoryStorage::new()))
// .try_build()?;
let token = StpUtil::login("10001").await?;
println!("token = {token}");
// 多账号:钉死 login_type
let admin = StpUtil::stp_logic("admin")?;
let admin_token = admin.login("10001").await?;
Ok(())
}- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
公开路由请记得:
PathAuthConfig::new()
.exclude("/api/login")
.exclude("/health");- 1
- 2
- 3
而不是指望单独一个 #[sa_ignore] 就能放行中间件。
你可以怎么开始
1. 新项目选型
直接上 0.2.0。从文档站 Quick start 进,按框架选插件 crate,Memory 开发、Redis 生产。
2. 0.1.x 存量项目
按 迁移指南 清单改:
- 依赖升到
0.2.0 *-core→plugin-common/ 插件 preludeinit_manager→try_init_manager- 公开路由 →
PathAuthConfig::exclude - 按需打开
auto_renew/token_prefix/is_write_cookie - OAuth2 / SSO 按新安全模型重读一遍
3. 关注开源与社区的朋友
旋武收录、G-Star 提名,证明项目进入了更广的开源视野;
0.2 的意义是:在被看见之后,把工程质量配得上这份看见。
我们真正想交付的,不只是「又一个 Auth 库」
认证授权框架的价值,从来不在「功能列表有多长」,而在于:
- 失败时会不会把半截状态写进 Redis;
- 换一个 Web 框架,行为会不会悄悄变;
- 默认配置会不会在你不知情时「每次读 Token 都写库」;
- 文档写的 API,能不能和 crates.io 上的二进制对得上。
sa-token-rust 0.2.0 做的,就是把这些问题从「靠经验躲开」变成「靠架构默认正确」。
欢迎 Star、提 Issue、提 PR;
也欢迎把文档站收藏进团队内部 Wiki——下次选型时,少踩一轮坑。
相关链接
| 说明 | 链接 |
|---|---|
| 正式文档(中英) | https://sa-tokens.github.io/sa-token-rust/ |
| 旋武社区收录页 | https://xuanwu.openatom.org/articles/project/sa-token-rust/ |
| AtomGit / G-Star 详情页 | https://atomgit.com/sa-tokens/sa-token-rust |
| GitHub 仓库 | https://github.com/sa-tokens/sa-token-rust |
| Gitee 仓库 | https://gitee.com/sa-tokens/sa-token-rust |
| Issues | https://github.com/sa-tokens/sa-token-rust/issues |
| 0.2 迁移说明 | MIGRATION_0.2.md |
| crates.io(搜索 sa-token) | 统一版本 0.2.0 |
设计灵感来自 Dromara sa-token;本仓库为 独立 Rust 实现,许可证 MIT OR Apache-2.0,详见仓库 NOTICE。
鲁公网安备37011202002956号