前言
本文谈谈 【JWT 的组成部分】 目标是看完之后,需要能用自己的语言说出【JWT 由哪几部分构成,各部分的作用是什么】
正文
JWT(JSON Web Token) 是一种开放标准(RFC 7519),它定义了一种紧凑的(Compact) 、自包含的(Self-contained) 方式,用于在各方之间安全地传输信息作为 JSON 对象。
这些信息可以被验证 和信任 ,因为它是数字签名 的。JWT 可以使用密钥(HMAC 算法) 或使用 RSA 或 ECDSA 的公钥/私钥对进行签名。
一个 JWT 实际上就是一个字符串,它由三部分组成,用点(.)分隔开,格式如下:
css
header.payload.signature
也就是:
xxxxx.yyyyy.zzzzz
这三部分分别是:
- Header (头部)
- Payload (有效载荷)
- Signature (签名)
下面我们来详细拆解每一部分。
1. Header (头部)
作用 :描述 JWT 的元数据(Metadata) ,最主要的是声明签名算法 和令牌类型。
- 典型内容 :
alg
(algorithm):签名使用的算法 。例如HS256
(HMAC SHA-256) 或RS256
(RSA SHA-256)。typ
(type):令牌类型 。通常就是JWT
。
- 数据处理流程 :
- 这个 JSON 对象会通过 Base64Url 编码(一种针对 URL 安全的 Base64 编码),形成 JWT 的第一部分。
示例: 一个原始的 Header JSON:
json
{
"alg": "HS256",
"typ": "JWT"
}
经过 Base64Url 编码后,得到 JWT 的第一部分:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
🔍 小提示!!!:Base64 是一种编码方式,不是加密!!!所以 Header 部分的内容任何人都可以解码看到。你可以直接把上面的编码字符串拿去任何在线 Base64 解码工具解码,就能还原出原始的 JSON。
2. Payload (有效载荷)
作用 :携带实际的声明(Claims)。声明就是关于实体(通常是用户)和其他数据的语句。
- 声明类型 :
- 注册声明(Registered Claims) :预定义的一组标准声明,非强制但推荐使用,用于提供一组有用的、可互操作的声明。
iss
(issuer):签发者。sub
(subject):主题(通常是用户 ID)。aud
(audience):接收方。exp
(expiration time):过期时间(Unix 时间戳)。nbf
(not before):生效时间,在此时间之前令牌无效。iat
(issued at):签发时间。
- 公共声明(Public Claims) :可以随意定义的声明,但为了避免冲突,应该在 IANA JSON Web Token Registry 中定义它们,或者使用一个防冲突的命名空间(如包含域名)。
- 私有声明(Private Claims) :在提供者和消费者之间共同约定 的、用于共享信息的自定义声明,既不是注册声明也不是公共声明。
- 例如:
username
,role
等。
- 例如:
- 注册声明(Registered Claims) :预定义的一组标准声明,非强制但推荐使用,用于提供一组有用的、可互操作的声明。
- 数据处理流程 :
- Payload 的 JSON 对象同样会通过 Base64Url 编码,形成 JWT 的第二部分。
示例: 一个原始的 Payload JSON:
json
{
"sub": "1234567890",
"name": "John Doe",
"iat": 1516239022,
"admin": true
}
经过 Base64Url 编码后,得到 JWT 的第二部分:eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJhZG1pbiI6dHJ1ZX0
⚠️ 重要提醒 :和 Header 一样,Payload 也仅仅是 Base64Url 编码 ,【并非加密】!!!。绝对不要在 JWT 的 Payload 或 Header 中放置敏感信息(如密码),除非整个 JWT 被额外加密了(参见 JWE)。
3. Signature (签名)
作用 :这是 JWT 的安全核心 。用于验证消息在传输过程中没有被篡改,并且对于使用私钥签名的令牌,它还可以验证发送方的身份。
- 生成方式 :
- 取编码后的 Header 、编码后的 Payload ,用一个点(.)连接起来,形成一个字符串:
base64UrlEncode(header) + "." + base64UrlEncode(payload)
。 - 使用在 Header 中指定的签名算法(如
HS256
),和一个密钥(Secret) 或私钥(Private Key) ,对这个连接起来的字符串进行签名。
- 取编码后的 Header 、编码后的 Payload ,用一个点(.)连接起来,形成一个字符串:
以 HS256 为例的签名公式:
scss
signature = HMACSHA256(
base64UrlEncode(header) + "." + base64UrlEncode(payload),
secret
)
然后将签名结果(一个二进制哈希值)也进行 Base64Url 编码,形成 JWT 的第三部分。
示例 : 假设我们的密钥是字符串 "your-256-bit-secret"。 对 eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJhZG1pbiI6dHJ1ZX0
进行 HMAC-SHA256 签名并编码后,得到第三部分:SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
🛡️ 核心价值 :签名是关键!即使 Header 和 Payload 可以被任何人解码查看,但无法被篡改。因为服务器在收到 JWT 后,会用同样的密钥和算法重新计算前两部分的签名,如果计算结果与第三部分不匹配,就说明令牌被篡改了,应立即拒绝。
最终的 JWT
将上面三个用点分隔的 Base64Url 字符串拼接起来,就形成了一个完整的 JWT:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJhZG1pbiI6dHJ1ZX0.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
我们可以用一个简单的流程图来回顾 JWT 的生成过程:
text
【生成 JWT】
┌─────────────────┐ ┌──────────────────┐ ┌──────────────────┐
│ 1. Header │ │ 2. Payload │ │ 3. Signature │
│ │ │ │ │ │
│ { │ │ { │ │ 取前两部分编码结果:│
│ "alg": "HS256",│ │ "sub": "123...", │ │ header_b64 + "." │
│ "typ": "JWT" │ │ "name": "Jo...", │ │ + payload_b64 │
│ } │ │ ... │ │ │
│ │ │ } │ │ 用密钥(Secret) │
└─────────────────┘ └──────────────────┘ │ 和Header中指定 │
| | │ 的算法(alg)进行 │
↓ (Base64Url 编码) ↓ (Base64Url 编码)│ 签名(HMAC等) │
┌─────────────────┐ ┌──────────────────┐ │ │
│ header_b64 │ │ payload_b64 │ │ 得到签名后同样 │
│ "eyJhbGc..." │ │ "eyJzdWI..." │ │ 进行Base64Url编码│
└─────────────────┘ └──────────────────┘ │ │
\_________________________/ └──────────────────┘
| |
↓ (用点 . 连接) ↓ (编码后)
header_b64 + "." + payload_b64 signature_b64
\_________________________ ________________/
|
↓ (最终用点 . 连接)
最终JWT = header_b64 + "." + payload_b64 + "." + signature_b64
验证 JWT 时,服务端会做反向操作:
- 将 JWT 按点分割成三部分。
- 用相同的密钥和算法,对前两部分重新计算签名。
- 将自己计算的签名与 JWT 自带的第三部分签名进行安全的比对(防止计时攻击)。
- 如果签名一致,则证明令牌有效且未被篡改;同时,可以解码 Payload 提取其中的信息(如用户 ID、权限等)。
最后
我们来回答开头的问题:JWT 由哪几部分构成,各部分的作用是什么?
JWT 由三部分组成,用点(.)分隔:
- Header(头部):经过 Base64Url 编码的 JSON 对象,主要声明签名算法(alg)和令牌类型(typ)。
- Payload(有效载荷):经过 Base64Url 编码的 JSON 对象,携带了实际的声明(Claims),如用户身份(sub)、过期时间(exp)等自定义信息。
- Signature(签名):对前两部分连接后的字符串,通过指定的算法和密钥进行签名并编码的结果,是验证令牌完整性和真实性的核心。
核心要点 :Header 和 Payload 仅是编码,不加密,切勿存放敏感信息。JWT 的安全性完全依赖于签名。