JWT 原理:Header、Payload 与 Signature
JWT(JSON Web Token)是一种紧凑的 Token 表示格式。常见的“签名 JWT”由三段组成,中间使用英文句点连接:
xxxxx.yyyyy.zzzzz
Header.Payload.Signature
1. Header
Header 描述 Token 使用的类型和签名算法:
{
"alg": "HS256",
"typ": "JWT"
}
alg:签名/MAC 算法。typ:媒体类型提示,常见值为JWT。
Header 会被 JSON 序列化并进行 Base64URL 编码。它不是秘密。
2. Payload
Payload 保存 Claims(声明),也就是 Token 要表达的信息:
{
"sub": "user-123",
"role": "user",
"iss": "nloop-api",
"aud": "nloop-client",
"iat": 1786492800,
"exp": 1786493700
}
常见注册声明:
| 声明 | 含义 | 示例用途 |
|---|---|---|
sub |
Subject,主体 | 用户 ID |
iss |
Issuer,签发方 | nloop-api |
aud |
Audience,接收方 | nloop-client |
iat |
Issued At,签发时间 | 计算 Token 年龄 |
exp |
Expiration Time,过期时间 | 超时后拒绝 |
nbf |
Not Before | 指定何时开始生效 |
jti |
JWT ID | Token 唯一标识 |
iat、exp、nbf 使用 NumericDate:从 Unix Epoch 开始计算的秒数,不是 JavaScript 常用的毫秒数。
Payload 可以放少量、非敏感且验证后确实需要的身份信息,例如用户 ID、Token 类型。不要放:
- 密码或密码哈希。
- JWT Secret、私钥。
- 身份证号、银行卡号等敏感资料。
- 经常变化且必须实时生效的大量业务数据。
3. Signature
以 HS256 为例,签名概念可简化为:
encodedHeader = base64Url(header)
encodedPayload = base64Url(payload)
signingInput = encodedHeader + "." + encodedPayload
signature = HMAC-SHA256(signingInput, secret)
最终 Token 是:
encodedHeader.encodedPayload.encodedSignature
如果攻击者把 role: "user" 修改成 role: "admin",但没有 Secret,就无法生成匹配的新签名。服务端调用 jwt.verify() 时会发现签名不一致。
4. 签名保护什么
签名可以帮助验证:
- Header 和 Payload 没有被篡改。
- Token 由掌握正确签名密钥的一方生成。
签名不能保证:
- Payload 不被读取。
- Token 不被复制。
- 被盗 Token 自动失效。
- Payload 中的权限永远与数据库一致。
因此 Bearer Token 必须通过 HTTPS 传输,并设置合理的过期时间。
5. decode() 为什么不可信
解码只做格式转换:
Base64URL 字符串 -> JSON
任何人都能构造三段字符串。jwt.decode() 不会证明签名正确,也不会把数据变成可信数据。
const payload = jwt.decode(token); // 只能查看
const payload = jwt.verify(token, secret); // 验证后才可能用于认证
即使通过 verify(),返回的数据仍来自外部请求。代码还应检查它是不是对象,以及 sub、tokenType 等业务字段是否存在且类型正确。
6. HS256 与 RS256
HS256
- HMAC + SHA-256。
- 签发和验证使用同一个 Secret。
- 配置简单,适合单体学习项目。
- 所有能验证 Token 的服务同时也具备签发能力。
RS256
- RSA + SHA-256。
- 私钥签发,公钥验证。
- 适合多个服务只需要验证、不能签发的场景。
- 需要管理密钥对和公钥轮换。
当前教程选择 HS256,是为了把注意力放在认证流程。生产系统应根据部署边界和密钥管理能力选择算法。
7. JWT、JWS 和 JWE
- JWT:一组 Claims 的表示规范。
- JWS:带数字签名或 MAC 的数据;日常所说的三段 JWT 通常属于这一类。
- JWE:加密的数据,结构和密钥管理更复杂。
jsonwebtoken 的主要用途是签发和验证 JWT/JWS,不应把它理解为“JWT 内容加密库”。
8. 无状态的含义
服务端验证 Access Token 时,可以只依赖签名密钥和 Token 本身,不一定查询会话表,这常被称为无状态认证。
但无状态也带来限制:已签发且尚未过期的 JWT 很难立即撤销。常见应对策略包括:
- Access Token 有效期保持较短。
- Refresh Token 使用服务端会话记录。
- 修改密码、封禁账号等高风险操作检查数据库状态。
- 必要时维护撤销列表或用户 Token 版本号。
因此,“使用 JWT”不等于“认证系统完全不需要数据库状态”。