JWT 详解:结构、声明和如何解码
更新 2026-07-06
如果你用过现代 Web API,就见过 JWT —— 那些带两个点、出现在登录响应和 Authorization 头里的一长串乱码。它们看着不透明,但只要你知道结构,就出奇地好读。本指南讲清什么是 JSON Web Token、里面有什么、签名如何工作,以及要避免的安全错误。
JWT 是做什么用的
JSON Web Token(JWT) 是一种紧凑、自包含的方式,用来携带一组声明 —— 诸如“这是用户 42,他在 10:05 登录”这样的陈述。它的主要用途是身份验证:你登录后,服务器签发一个 JWT,你的应用在每次请求时把它带回,服务器就信任它,而不必每次都去会话存储里查你。因为令牌本身携带信息,所以被称为 无状态(stateless)。
三个部分
每个 JWT 都是三段用点连接的 Base64URL 编码段:header.payload.signature。
eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiI0MiJ9.3x9kQ... └──── header ────┘ └── payload ──┘ └ signature ┘
1. 头部(Header)
关于令牌的元数据 —— 签名算法(alg,例如 HS256)和类型(typ: JWT)。解码后,它只是一小段 JSON:
{ "alg": "HS256", "typ": "JWT" }2. 载荷(Payload)
声明 —— 实际的数据。有些名字是标准化的(称为注册声明):
sub—— 主体(subject),通常是用户 ID。iss—— 签发者(issuer),谁创建了令牌。aud—— 受众(audience),它是给谁的。exp—— 过期时间(一个 Unix 时间戳)。iat—— 签发时间(一个 Unix 时间戳)。
那些 exp 和 iat 的值是自 1970 年以来的秒数 —— 如果你需要把它们读成真实日期,时间戳转换器 会把它们变成人类可读的时间。
3. 签名(Signature)
签名是让令牌可信的东西。签发者拿着头部和载荷,用一个密钥生成一个加密签名。持有密钥的任何人都能验证头部和载荷没有被篡改 —— 只要改动载荷里的一个字符,签名就不再匹配。
最重要要理解的一点
JWT 是被签名的,不是被加密的。 头部和载荷只是被 Base64URL 编码,这意味着 任何人 都能解码并读取它们 —— 无需密钥。签名防止 篡改,而不是 读取。
实际后果:永远不要把机密放进 JWT 载荷。没有密码、没有信用卡号、没有私密数据 —— 假设载荷是公开的。你可以把任意令牌粘进我们的 JWT 解码器 亲自确认,它会即时读出头部和声明,全程在你的浏览器中(令牌绝不离开你的设备)。底层不过是 Base64 解码 —— 解码器只是替你省了这些步骤。
验证 vs. 解码
这是两种不同的动作,把它们搞混是一个真实的安全漏洞。解码 读取载荷 —— 任何人都能做,且什么也证明不了。验证 用密钥检查签名,确认令牌是真实且未被改动的。服务器在信任之前必须 验证 每一个令牌;只解码不是身份验证。
常见陷阱
- 信任一个未经验证的令牌 —— 在依据声明行动前,务必在服务器端检查签名。
- 忽略过期 —— 尊重
exp;一个过期的令牌应当被拒绝。 - 把敏感数据存进载荷 —— 它对任何人可读。
- `alg: none` 陷阱 —— 一些库曾经接受声称“无签名”的令牌。拒绝它们,并锁定预期的算法。
理解这些,JWT 就从吓人的字符串变成一个简单、透明的格式:可读的声明,由一个你必须在信任前验证的签名来保护。
更多 网络与开发者
查看全部 网络与开发者 指南 →本指南提到的工具