自包含的凭证

另一种思路:把身份写进 Token

服务端要查存储才能识别用户,多少有点麻烦。有没有办法让 Token 自己就能证明身份?

JWT(JSON Web Token)就是这种思路:把用户身份和过期时间写进 Token,再用签名防止篡改。服务端只要验签通过,就能直接从 Token 里读出「这是谁、什么时候过期」,不一定需要查数据库。

一个 JWT 长这样,分三段:

header.payload.signature

header:   {"alg":"HS256","typ":"JWT"}
payload:  {"sub":"123456","name":"张三","exp":1710000000}
signature: HMAC-SHA256(header.payload, secret)

好处:无状态、可跨服务

  • 跨服务验证:任何服务只要有密钥,就能本地验签,不需要访问会话存储。
  • 减少查询:省掉每次请求查 Redis 的成本和依赖。
  • 适合分布式:几十个微服务都能独立验证身份,天然适配微服务架构。

代价:撤销很难

这是 JWT 最核心的痛点。签名有效的 JWT,在过期之前一直有效——因为验证方是无状态的,它不知道「这个 Token 是不是已经被撤销了」。

用户登出、改密码、账号被冻结,这些撤销操作对已签发的 JWT 不会立即生效。典型后果:

  • 用户点了「退出登录」,但手里的 JWT 还能用一段时间。
  • 账号被盗后,即使改了密码,攻击者手里的旧 JWT 仍然有效。

缓解撤销难的办法

无状态是 JWT 的本质,所以只能「绕」:

办法思路代价
短有效期Access Token 只活几分钟撤销窗口短,但刷新频繁
黑名单把撤销的 jti 记到 Redis,验签时查又变回有状态
版本号用户表存 token_version,JWT 里带上,校验版本需要查库比对版本

这些办法都在「无状态」和「可撤销」之间做折中——越要可撤销,就越要向有状态妥协。

什么时候用 JWT

JWT 适合:

  • 大量服务需要独立、快速验证身份(网关、微服务、第三方开放平台)。
  • 能接受撤销有延迟,或用短有效期 + 版本号控制风险窗口。
  • 需要在多个系统间传递身份信息。

如果你的核心诉求是「随时能收回凭证」(账号安全要求高),JWT 反而不是首选。

两种方案放一起看

把不透明 Token 和 JWT 放在同一张表里对比,取舍就很清楚了:

方案对比

不透明 Token vs JWT

维度
不透明 Token
JWT
撤销能力
优随时可撤销,改状态即可
中困难,过期前仍有效
跨服务验证
中每次请求都要查服务端
优验签即可,无需查库
服务端存储
中需要数据库 / 缓存存状态
优无状态,不占存储
性能成本
中每次请求多一次查询
优验签快,但 Token 体积大
结论:没有绝对优劣,关键看撤销需求与 是否跨服务。高安全场景常用「短期 JWT + 服务端会话」组合。

一个小提示

JWT 的 payload 只是 Base64 编码,不是加密。任何拿到 Token 的人都能直接读出来。所以:

  • 不要往 payload 里放密码、手机号等敏感信息。
  • 密钥要足够强、定期轮换,用 HS256/RS256 等正规算法,不要用 none 算法。
  • 永远校验 alg,防止算法混淆攻击。

下一节看生产系统最常见的组合:把 Access Token 和 Refresh Token 拆开用。

发现内容有问题?

告诉我们哪里需要改进。