2. JWT 基础回顾:JWT 结构、签发与验证流程

JSON Web Token(JWT)是目前分布式系统中最常用的无状态身份令牌格式。在深入缓存一致性测试之前,必须彻底理解 JWT 的物理结构、生命周期以及标准库的行为差异。本节从三个维度展开:令牌结构、签发验证流程、主流库的选型要点。

2.1 JWT 结构:三段式编码

一个标准的 JWT 由三个 Base64URL 编码的片段组成,以点号(.)分隔:

eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0.
POstGetfAytaZS82wHcjoTyoqhMyxXiWdR7Nn7A29NSlwEi4uUNkH3gxvN3Oe0L82FwHcjoTyoqhMyxXiWdR7Nn7A29NSlwEi4uUNkH3gxvN3Oe0L8
部分 名称 内容示例 作用
Header 令牌头 {"alg":"RS256","typ":"JWT","kid":"key-1"} 声明签名算法和密钥标识
Payload 载荷 {"sub":"user_01","role":"admin","iat":1700000000,"exp":1700003600} 携带用户身份、权限和声明(Claims)
Signature 签名 Base64URL 编码的 HMAC/RSA/ECDSA 输出 防止篡改,验证令牌完整性
关键区别:Header 和 Payload 仅做 Base64URL 编码,不是加密。任何拿到令牌的人都可以解码读取内容。敏感信息(如密码、手机号)必须放在服务端 Session 中,或使用 JWE(JSON Web Encryption)加密整个载荷。
JWT 三段式结构拆解 Header alg: RS256 typ: JWT kid: key-1 Payload sub: user_01 role: admin exp: 1700003600 Signature HMAC-SHA256 或 RSA 签名 防篡改 Base64URL 编码(非加密) + 签名 = 完整 JWT

2.2 JWT 签发与验证流程

JWT 的生命周期分为两个阶段:签发(Issuance)和验证(Verification)。在缓存一致性测试中,这两个阶段的时序和状态管理是核心关注点。

2.2.1 签发流程(Issuance)

  1. 用户认证:客户端提交凭证(用户名/密码、授权码等)到认证服务器。
  2. 构建载荷:服务器生成 Claims,至少包含 sub(主体)、iat(签发时间)、exp(过期时间)。
  3. 选择密钥:根据 Header 中的 kid 或默认策略,从密钥存储中取出签名密钥。
  4. 计算签名:对 Base64URL(Header) + "." + Base64URL(Payload) 使用指定算法生成签名。
  5. 组装令牌:将三段用点号拼接,返回给客户端。

2.2.2 验证流程(Verification)

  1. 解析令牌:按点号分割,分别 Base64URL 解码 Header 和 Payload。
  2. 获取密钥:根据 Header 中的 alg 和 kid,从信任的密钥源(本地密钥、JWKS 端点)获取公钥或对称密钥。
  3. 签名校验:使用相同算法重新计算签名,与令牌携带的签名比对。
  4. 声明校验:检查 exp(是否过期)、nbf(是否早于生效时间)、iss(签发者是否匹配)、aud(受众是否包含当前服务)。
  5. 通过/拒绝:全部通过则信任令牌内容,提取用户身份;否则返回 401 错误。
缓存一致性测试关注点:验证阶段涉及 密钥获取 和 令牌黑名单 两个缓存点。如果密钥缓存与 JWKS 端点不一致,或黑名单缓存未及时同步,会导致已撤销的令牌被误认为有效,或有效令牌被错误拒绝。
JWT 签发与验证双流程 签发流程(Issuance) ① 用户认证(凭证验证) ② 构建 Claims(sub/iat/exp) ③ 选择签名密钥(kid 匹配) ④ 计算签名(HMAC/RSA/ECDSA) ⑤ 返回 JWT 给客户端 验证流程(Verification) ① 解析 Header 和 Payload ② 获取公钥/密钥(JWKS 或本地) ③ 签名校验(防篡改) ④ 声明校验(exp/nbf/iss/aud) ⑤ 通过 → 提取身份 / 拒绝 → 401

2.3 常见 JWT 库介绍

不同语言和框架的 JWT 库在缓存行为、密钥轮换支持、性能方面存在显著差异。以下是测试中需要重点关注的库及其特性:

语言 库名 签名算法支持 缓存特性 测试关注点
Java jjwt (0.12.x) HS256/RS256/ES256/EdDSA 内置 JWKS 缓存(可配置 TTL) 缓存刷新时机、并发下缓存穿透
Java Nimbus JOSE+JWT 全算法 + 加密 JWE JWKSet 缓存 + 远程加载器 远程缓存与本地缓存一致性
Go golang-jwt/jwt/v5 HS/RS/ES/EdDSA 无内置缓存,需自行实现 自定义缓存实现是否正确
Python PyJWT HS/RS/ES/EdDSA 无内置缓存 密钥获取延迟对验证性能的影响
Node.js jsonwebtoken HS/RS/ES 无内置缓存 多实例下密钥同步问题
.NET System.IdentityModel.Tokens.Jwt HS/RS/ES ConfigurationManager 内置缓存 缓存过期后自动刷新是否原子
测试策略提示:在缓存一致性测试中,优先选择 jjwt(Java)和 System.IdentityModel.Tokens.Jwt(.NET)作为被测对象,因为它们内置了缓存机制,更容易暴露缓存不一致的边界场景。对于无内置缓存的库(如 PyJWT、jsonwebtoken),测试重点应放在外部缓存层(Redis/Memcached)与验证逻辑的集成正确性上。

2.4 本节小结

  • JWT 由 Header、Payload、Signature 三段组成,Base64URL 编码仅做序列化,不提供机密性。
  • 签发流程依赖密钥选择与签名计算;验证流程依赖密钥获取与声明校验,这两个阶段都可能引入缓存。
  • 不同 JWT 库的缓存策略差异很大:有的内置 JWKS 缓存(jjwt、Nimbus、.NET),有的完全无缓存(PyJWT、jsonwebtoken)。
  • 缓存一致性测试的核心场景包括:密钥缓存刷新延迟、令牌黑名单同步、多实例缓存穿透。