为什么 JWT 难以主动吊销,而云厂商的 API Key 却能一键删除?

在《登录的过程中,后端发生了什么?》提到:Session 可以「删 session 即失效」,而 JWT 则「难以主动吊销」。
——同样是 Key,为什么云厂商控制台里的 API Key 点一下删除立刻失效?

同为凭证,吊销难度天差地别

先看两个场景:

场景 A(JWT):用户登录后,后端签发了一个有效期 7 天的 JWT。突然用户怀疑自己账号被盗,要求立即踢掉所有会话。你翻遍代码发现——只要 Token 没过期、签名是对的,服务器就认账,你没有任何办法让这个 Token 立刻失效,只能等它自然过期,或者动用密钥轮换这种「伤及全员」的手段。

场景 B(云厂商 API Key):你在云厂商控制台(AWS / 阿里云 / 腾讯云)里给某台 CI 机器配置了一个 AccessKey。后来发现它被泄露在 GitHub 上。你在控制台点一下「禁用」甚至「删除」,从这一刻起,所有用这个 Key 发起的请求立刻返回 401,马上生效。

两者都是「身份凭证」,为什么吊销能力差距如此之大?答案藏在有状态与无状态的校验模型里。

JWT 为什么难以主动吊销

2.1 无状态模型:服务器「不记得」签过哪些 Token

JWT 是自包含令牌:所有身份、权限、过期时间全部编码在 token 字符串本身。
正常无状态模式:服务端不需要查数据库,只校验签名 +exp过期时间,就放行请求。
问题:令牌一旦签发,字符串本身不会变。就算后台把用户禁用,只要签名合法、没过期,JWT 依然能通过校验。
想要吊销,就必须强行引入状态:维护 jti 黑名单、token 版本号,每次请求查缓存 / 数据库,此时就丢掉了 “无状态” 的优势。
一句话:无状态 = 校验逻辑完全不依赖服务端存储,所以没法单方面废掉已下发的 token。

2.2 想吊销 JWT 的补救方案,各自都有代价

方案 做法 代价
短有效期 + Refresh Token JWT 只活几分钟,续期靠 Refresh Token(常做成有状态) 只能「缩短吊销窗口」,做不到即时吊销;多一次刷新请求
黑名单(按 jti) 吊销时把 Token 的 jti 写入 Redis,验签后查一次黑名单 每次请求多一次存储访问,JWT 已「半有状态」,还失去无状态扩展优势
全局密钥轮换 换签名密钥,所有旧 Token 全部失效 伤敌一千自损八百,全体用户被迫重新登录

注意黑名单方案:一旦引入黑名单,JWT 就不再是纯无状态了——服务器必须记住「哪些 Token 被吊销了」。

云厂商的 API Key 为什么能「删除即生效」

3.1 API Key 是什么

云厂商的长期凭证通常是一对 AK/SK(如 AWS 的 Access Key ID + Secret Access Key、阿里云的 AccessKeyId + AccessKeySecret),也可能是一个单字符串 Token。它本质上是静态的、长期有效的「机器身份凭证」,绑定了用户/角色与权限策略。

调用云 API 时,客户端用 SK 对请求做签名,把 AK(+ 签名)随请求带上;云端拿到后校验签名与权限。

3.2 关键:云端有一张「权威台账」

与 JWT 不同,云厂商在权威数据库 / 缓存里维护着每一把 Key 的完整台账:

  • Key 本身(AK)
  • 状态:启用 / 禁用 / 已删除
  • 绑定的账号或角色、权限策略
  • 创建时间、最后使用时间等审计信息

每一次 API 请求,云端都会查这张台账

flowchart TD
    C[请求携带 AK/SK 签名] --> S[云厂商鉴权服务]
    S --> DB[查台账: Key 存在吗?]
    DB --> Q{状态为启用?}
    Q -->|否| R[拒绝 403]
    Q -->|是| V[验签名]
    V --> P[查权限策略]
    P --> OK[放行]

「删除」这个动作的本质,只是把台账里这一行记录的状态改为禁用或删掉。下一次校验时:查不到记录 / 查到已禁用 → 直接拒绝。这就是为什么云厂商的 Key 能做到「删除即生效」。

类比:JWT 是「拿着章到处认账的欠条」,API Key 是「一把需要回后台档案室核对的门禁卡」。门禁卡本身不决定能不能进门,决定权在档案室的那条记录里——而档案室是可以随时改的。

正因为每次请求都要查台账,云厂商鉴权服务是全链路的高频热点,通常会用 Redis / 内存缓存 + 异步同步来扛住这个查询压力。
分布式网关会有缓存传播延迟,部分云厂商删除密钥后短时间(几分钟级别)老缓存还会放行,不是即时 100% 全局生效。

无状态验证 vs 有状态验证

把两者放在一起,差异一目了然:

维度 JWT 云厂商 API Key
校验方式 本地验签,不查库 查库/缓存中的台账
校验成本 O(1),无网络依赖,极快 一次存储访问
吊销方式 只能等过期 / 黑名单 / 轮换密钥 改台账状态,立即生效
吊销时效 秒级到分钟级(黑名单)甚至无法即时 即时
服务器状态 无状态,天然易水平扩展 有状态,鉴权服务是热点
审计/管控 弱(服务器不知有哪些 Token 在流通) 强(每把 Key 有台账、可审计)

可以看到,这是一枚硬币的两面:

  • JWT 把「验证成本」压到极致——本地验签、无共享存储、天然易扩展,代价是放弃「即时吊销」。
  • API Key 把「吊销能力」拉满——改库即生效、台账可审计,代价是每次请求都要访问一次集中存储。

为什么不能「两全其美」?

能不能既要 JWT 的验签快、又要 API Key 的即时吊销?

要看清两个约束:

  • 即时吊销的前提:服务器必须知道「当前哪些凭证已被撤销」→ 必须有共享的可变状态
  • 无状态验签的前提:服务器不依赖任何可变状态 → 不知道凭证是否被撤销。

「全程无状态」与「即时吊销」在根本上是冲突的——这就是分布式系统里常见的权衡:凭证的验证成本 vs 管控能力,只能做取舍。

不过现实中有成熟的折中方案,思路是:凭证本身无状态 + 校验点有状态。即保留 JWT 验签快、载荷自包含的优点,只对「极少数被撤销的凭证」增加一次集中查询:

折中方案 原理 效果
黑名单(jti) 只记录被吊销的 Token,其余不查库 大多数请求仍无状态,仅被吊销者多一次查询
会话版本号 用户级 version 存 Redis/DB,吊销时 +1,JWT 载荷里带版本号 吊销某用户全部会话 = 一次自增,验签后比对版本号即可

这类方案在大型系统中很常见:登录态用短 TTL JWT + 有状态 Refresh Token + 可选的会话版本号,既有无状态校验的扩展性,又保留了「踢人下线」的管控能力。

适用场景:什么时候选谁

适合 JWT 的场景

  • 微服务之间信任传递、内部调用,多实例无共享存储时天然扩展
  • 登录态(配合短有效期 + Refresh Token,接受吊销延迟)
  • 对「单次验证速度」和「无状态架构」有硬性要求

适合「有状态 API Key 台账」模型的场景

  • 云平台 / 开放平台第三方接入,需要按应用隔离、随时撤销、审计溯源
  • 机器身份(CI/CD、服务间调用、SDK 接入),泄露后必须能立即止血
  • 任何「一旦泄露必须马上作废」的安全敏感场景

一句话选型:追求验证快、架构简单、可接受吊销延迟,用 JWT;追求即时撤销与强管控,就必须接受有状态的台账校验

小结

JWT 云厂商 API Key
为什么难/易吊销 服务器不存签发记录,无法点名作废 云端维护 Key 台账,改状态即失效
本质 无状态验签 有状态查台账
核心权衡 验证快 vs 管控强 管控强 vs 单点查询成本

回到开头的问题:JWT 难吊销,是因为它「不记得」自己签发了什么;API Key 能一键删除,是因为云端「记得」每一把钥匙的状态。 所谓凭证,本质上是「验证端信不信你」的问题——信之前要不要去查一下台账,决定了你能不能在几毫秒内让它作废。