令牌类型选型:JWT、Opaque 、Paseto、SAML

说实话,选令牌类型是令牌化设计里最纠结的一步。我记得有个项目上线前一周还在纠结用JWT还是Opaque ,最后选了后者,因为客户要求能随时撤销令牌。今天我就带你把主流四种令牌类型挨个扒一扒。

JWT(JSON Web )

JWT 现在太火了,几乎成了 API 令牌的默认选项。它的核心特点是自包含——令牌本身存了用户信息、过期时间、权限范围,服务端不用查数据库就能验证。

维度说明
优点无状态、跨语言、可包含自定义声明、支持签名和加密
缺点负载无法撤销(除非黑名单)、令牌体积大、签名验证有性能开销
适用场景短时效令牌、微服务间认证、移动端
⚠️ 避坑指南
我曾经在项目里直接用 JWT 的 payload 存了大段用户权限列表,结果 大小飙到 4KB,每次请求都传输,带宽白白浪费。后来改成只存 role_id,接口再查权限。

为什么说 JWT 难撤销?因为它本身就是个「活期存单」,到期前谁拿着都能用。你想想看,如果用户改了密码,旧 依然有效,得把签发密钥改了才行。我的习惯是 JWT 过期时间控制在 15 分钟以内,配合 refresh 做长生命周期。

Opaque (不透明令牌)

说白了就是个随机字符串,像个房间钥匙——你看到钥匙也不知道哪个房间,得拿到前台(授权服务器)查一下。这种令牌就是一把无意义的 ID,所有信息都保存在服务端。

💡 什么时候选它?
需要支持令牌撤销、需要控制令牌生命周期、多端共享令牌状态。比如 OAuth 2.0 的 Bearer 默认就是不透明的。
维度说明
优点可撤销、体积小(通常 32-64 字节)、无信息泄露风险
缺点需查数据库 / 缓存、增加网络延迟、依赖中心化存储
适用场景会话管理、高安全性要求、需要即时失效

我个人习惯在微服务网关层做 Opaque 的校验——网关统一查 Redis,后端服务直接信任网关传过来的用户信息。这样后端服务不用改代码就能全局控制令牌。

Paseto(Platform-Agnostic Security )

我记得第一次看到 Paseto 是 2019 年,当时 JWT 的漏洞层出不穷(alg=none、密钥混淆),Paseto 的创建者直接说:「JWT 的设计是失败的」。Paseto 把加密和签名算法固化为两种模式:本地模式用对称加密,公共模式用非对称签名。你没法选「无签名」这种邪恶选项。

维度说明
优点安全默认、算法固定、防止签名混淆、版本化设计
缺点生态较小(库少)、社区支持弱、学习曲线陡
适用场景对安全极端敏感、新项目可接受额外复杂度
🔐 一点经验
我曾经在内部工具链里尝试用 Paseto 替换 JWT,发现 Go 和 Python 的库都挺成熟了,但 Java 库还不太稳定。如果团队全是 Java 生态,建议再观望。

SAML(Security Assertion Markup Language)

SAML 是「上一代」的令牌标准,主要用在企业级单点登录(SSO)。它基于 XML,结构臃肿,一个断言动不动就几十 KB。嗯,现在除了金融、政府老系统,基本没人用它做 REST API 令牌。

维度
优点支持跨域 SSO、标准成熟、支持复杂的属性映射
缺点XML 解析慢、体积大、移动端不友好、配置繁琐
适用场景遗留企业系统集成、政府 / 金融内部 SSO(非 API 调用)

你想想看,移动端一个 50KB 的 SAML 断言传回来,网络稍微差一点就超时了。所以 REST API 场景下我基本不考虑它,除非客户明确要求对接老旧的 SAML IdP。

四种令牌类型对比总览

类型存储方式可撤销体积安全等级生态成熟度
JWT自包含否(需黑名单)大(通常 1-2KB)中等⭐⭐⭐⭐⭐
Opaque服务端是小(32-64B)高⭐⭐⭐⭐⭐
Paseto自包含否(同 JWT)小(类似 JWT)高⭐⭐⭐
SAML自包含否极大(10KB+)高⭐⭐⭐⭐

实战选型流程图

下面这张图能帮你快速决策。我每次做架构评审都会走一遍这个流程。

令牌类型选型决策流程 是否需要撤销令牌? 否 对安全极端敏感? 否 JWT 是 Paseto 是 需要企业SSO集成? 否 Opaque 是 SAML 📌 决策说明 1. 需要撤销 → 选 Opaque ,服务端存储实时状态 2. 不需要撤销 → 优先 JWT(生态好),安全敏感选 Paseto 3. 遗留企业 SSO → 只能选 SAML(但尽量迁移到 OAuth 2.0) 📊 实测参考(我自己的压测数据) · JWT 签名验证:0.12ms(RS256)/ 0.03ms(HS256) · Opaque Redis 查询:0.4ms(本地)~ 2ms(跨机房) · Paseto 本地模式:0.05ms;SAML 解析:15ms+

选型建议

  1. 普通 Web API / 移动端:JWT + 短过期(15分钟),用 refresh 延长。我见过大量项目这样跑,没什么大问题。
  2. 高安全场景(金融、医疗):Opaque 为主,配合 Redis 存储,支持即时撤销。成本是每次请求多一次网络开销,但安全换性能值得。
  3. 新项目想尝鲜:可以试试 Paseto。不过要做好库出问题时的降级预案,我就是因为找不到好用的 .NET 库才放弃的。
  4. 与遗留 SSO 对接:SAML 逃不掉,但尽量在 API 网关处转成内部 JWT,别让下游服务直接处理 SAML。
💡 一个折中技巧
你可以用 Opaque 做入口令牌(接收端校验),然后在网关内部签发一个短时效 JWT 给下游微服务。这样既支持撤销,又享受 JWT 的无状态便利。

嗯,四种令牌的对比就这些了。没有银弹,只有权衡。下回你做设计时带着这张决策图走一遍,基本不会跑偏。对了,记得把令牌的序列化和签名算法也写进 API 文档,我曾经遇到过服务端升级算法后客户端没更新,直接 401 一片红……