2. JWT 结构详解:Header、Payload、Signature 的组成与作用
JWT(JSON Web Token)是一种紧凑的、URL 安全的令牌表示方式,用于在各方之间以 JSON 对象的形式安全传输信息。一个标准的 JWT 由三个独立的部分组成,以点号(.)分隔:Header(头部)、Payload(载荷)、Signature(签名)。其典型结构如下:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
关键认知: JWT 的每一部分都是 Base64URL 编码后的字符串。Base64URL 编码与标准 Base64 编码类似,但将
+ 替换为 -,将 / 替换为 _,并去除末尾的 =,使其可以安全地用于 URL 查询参数和 HTTP 头部。
2.1 Header(头部)
Header 是 JWT 的第一部分,通常包含两个主要字段:令牌类型(typ)和签名算法(alg)。它告诉接收方如何解析和验证这个令牌。
| 字段 | 含义 | 示例值 | 说明 |
|---|---|---|---|
alg |
签名算法 | HS256、RS256、ES256 |
必选字段。指定生成签名所使用的算法。HS256 为对称算法,RS256/ES256 为非对称算法。 |
typ |
令牌类型 | JWT |
可选但推荐。声明该令牌为 JWT,帮助解析器快速识别。 |
cty |
内容类型 | JWT |
可选。当 JWT 被嵌套签名或加密时使用,表示嵌套内容的类型。 |
性能关注点:
alg 字段的选择直接影响鉴权性能。对称算法(如 HS256)计算速度快,但需要服务端和客户端共享密钥,在分布式系统中密钥分发困难。非对称算法(如 RS256)计算速度较慢(约慢 2-5 倍),但允许服务端只持有公钥,客户端持有私钥,更适合微服务架构。
// 一个典型的 Header 示例(解码后)
{
"alg": "RS256",
"typ": "JWT"
}
// Base64URL 编码后:eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9
2.2 Payload(载荷)
Payload 是 JWT 的核心数据部分,包含一组声明(Claims)。声明是关于实体(通常是用户)和附加数据的陈述。JWT 规范定义了三种类型的声明:注册声明、公共声明、私有声明。
2.2.1 注册声明(Registered Claims)
这是一组预定义的、非强制但推荐使用的声明,提供互操作性。它们通常以三个字母的缩写表示。
| 声明 | 全称 | 含义 | 性能/安全影响 |
|---|---|---|---|
iss |
Issuer | 签发者,标识签发 JWT 的实体 | 用于路由验证,减少跨域查询 |
sub |
Subject | 主题,标识 JWT 所面向的用户 | 通常为用户 ID,影响查询索引效率 |
aud |
Audience | 接收方,标识 JWT 的预期接收者 | 防止令牌被其他服务滥用 |
exp |
Expiration Time | 过期时间(Unix 时间戳) | 过期时间越短,验证频率越高,但安全性越好 |
nbf |
Not Before | 生效时间(Unix 时间戳) | 令牌在此时间之前不可用 |
iat |
Issued At | 签发时间(Unix 时间戳) | 用于计算令牌年龄和刷新策略 |
jti |
JWT ID | 令牌唯一标识符 | 用于防止重放攻击,需配合服务端存储 |
2.2.2 公共声明(Public Claims)
公共声明由 IANA JSON Web Token Claims 注册表定义,或使用 URI 作为名称以避免冲突。例如:name、email、role。
2.2.3 私有声明(Private Claims)
私有声明是服务提供方自定义的字段,用于在通信双方之间共享特定数据。例如:department、permissions。
安全警告: Payload 仅经过 Base64URL 编码,并未加密。任何人都可以解码并读取其中的内容。切勿在 Payload 中存放密码、密钥、信用卡号等敏感信息。如果需要保护数据内容,应使用 JWE(JSON Web Encryption)。
// 一个典型的 Payload 示例(解码后)
{
"sub": "1234567890",
"name": "John Doe",
"iat": 1516239022,
"exp": 1516242622,
"role": "admin",
"permissions": ["read:users", "write:users"]
}
// Base64URL 编码后:eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOjE1MTYyNDI2MjIsInJvbGUiOiJhZG1pbiIsInBlcm1pc3Npb25zIjpbInJlYWQ6dXNlcnMiLCJ3cml0ZTp1c2VycyJdfQ
2.3 Signature(签名)
Signature 是 JWT 的第三部分,用于验证消息在传输过程中未被篡改,并确认 JWT 确实来自预期的签发者。签名的生成过程如下:
- 将 Base64URL 编码后的 Header 和 Payload 用点号(.)连接起来,形成签名输入字符串。
- 使用 Header 中指定的算法(
alg)和一个密钥(对称或非对称)对上述字符串进行签名。 - 将生成的签名进行 Base64URL 编码,得到最终的 Signature 部分。
// 签名生成伪代码
signatureInput = base64UrlEncode(header) + "." + base64UrlEncode(payload)
signature = HMACSHA256(signatureInput, secretKey) // 以 HS256 为例
signatureBase64 = base64UrlEncode(signature)
性能关键点: 签名验证是 JWT 鉴权中最耗时的操作。在分布式系统中,每次请求都需要验证签名。对于高并发场景,建议:
• 使用对称算法(HS256)时,将密钥缓存在本地内存,避免每次验证都读取配置中心。
• 使用非对称算法(RS256)时,缓存公钥并定期刷新,减少公钥获取的 I/O 开销。
• 考虑使用硬件安全模块(HSM)加速签名运算,但需评估成本与延迟。
• 使用对称算法(HS256)时,将密钥缓存在本地内存,避免每次验证都读取配置中心。
• 使用非对称算法(RS256)时,缓存公钥并定期刷新,减少公钥获取的 I/O 开销。
• 考虑使用硬件安全模块(HSM)加速签名运算,但需评估成本与延迟。
2.4 三部分协同工作
JWT 的三个部分共同构成了一个自包含的令牌。服务端无需查询数据库即可验证用户身份:
- Header 告诉服务端使用什么算法验证签名。
- Payload 包含用户身份和权限信息,服务端直接从中提取数据。
- Signature 确保 Header 和 Payload 未被篡改,并验证令牌来源。
性能优化建议: 在分布式鉴权场景中,建议将 Payload 的大小控制在 1KB 以内。过大的 Payload 会增加网络传输延迟和 Base64 编解码开销。对于需要携带大量权限信息的场景,可以考虑在 Payload 中只存放角色 ID,权限详情通过缓存或数据库按需加载。
| 部分 | 编码方式 | 是否加密 | 是否可篡改 | 主要作用 |
|---|---|---|---|---|
| Header | Base64URL | 否 | 是(被签名保护) | 声明算法和类型 |
| Payload | Base64URL | 否 | 是(被签名保护) | 携带用户声明数据 |
| Signature | Base64URL | 否 | 否(篡改后验证失败) | 验证完整性和来源 |