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)加密整个载荷。
2.2 JWT 签发与验证流程
JWT 的生命周期分为两个阶段:签发(Issuance)和验证(Verification)。在缓存一致性测试中,这两个阶段的时序和状态管理是核心关注点。
2.2.1 签发流程(Issuance)
- 用户认证:客户端提交凭证(用户名/密码、授权码等)到认证服务器。
- 构建载荷:服务器生成 Claims,至少包含
sub(主体)、iat(签发时间)、exp(过期时间)。 - 选择密钥:根据 Header 中的
kid或默认策略,从密钥存储中取出签名密钥。 - 计算签名:对
Base64URL(Header) + "." + Base64URL(Payload)使用指定算法生成签名。 - 组装令牌:将三段用点号拼接,返回给客户端。
2.2.2 验证流程(Verification)
- 解析令牌:按点号分割,分别 Base64URL 解码 Header 和 Payload。
- 获取密钥:根据 Header 中的
alg和kid,从信任的密钥源(本地密钥、JWKS 端点)获取公钥或对称密钥。 - 签名校验:使用相同算法重新计算签名,与令牌携带的签名比对。
- 声明校验:检查
exp(是否过期)、nbf(是否早于生效时间)、iss(签发者是否匹配)、aud(受众是否包含当前服务)。 - 通过/拒绝:全部通过则信任令牌内容,提取用户身份;否则返回 401 错误。
缓存一致性测试关注点:验证阶段涉及 密钥获取 和 令牌黑名单 两个缓存点。如果密钥缓存与 JWKS 端点不一致,或黑名单缓存未及时同步,会导致已撤销的令牌被误认为有效,或有效令牌被错误拒绝。
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)。
- 缓存一致性测试的核心场景包括:密钥缓存刷新延迟、令牌黑名单同步、多实例缓存穿透。