这是 Beta 探索课程,内容结构、实验步骤和示例可能会继续调整。
自包含的凭证
另一种思路:把身份写进 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 拆开用。
发现内容有问题?
告诉我们哪里需要改进。
