前后端联调时最常做的一件事:后端返回了一个 JWT token,你要解码看看里面 payload 有没有、header 是什么算法、signature 签了没、过期时间戳什么时候。JWT 解码的坑虽然不多,但一旦踩了就莫名其妙——"明明签名是对的为什么还是 Invalid Signature"。

这篇文章把 JWT 三段的拆解讲透,配合在线解码工具把"看不懂的 token"快速变成 JSON。

JWT 三段结构

eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
│                     │                                              │
└────── header ──────┘ └────────── payload ──────────────────────────┘ └── signature ──┘

每一段都是 Base64URL 编码(注意:不是标准 Base64,有 3 处差异:- 换 +、_ 换 /、去掉了 = 填充)。

解码步骤:

  1. 按 . 切成三段
  2. 对每段做 Base64URL 解码(-→+、_→/、补 = 填充到 4 倍数长度)
  3. header 和 payload 是 JSON,signature 是纯二进制字节

Header 段:算法和类型

{
  "alg": "HS256",   // 签名算法:HS256 / RS256 / ES256 / none
  "typ": "JWT"     // 类型,固定是 JWT
}

常见坑:"alg": "none" ——某些旧 JWT 库支持"无签名"模式,这种 token 任何人都能伪造。生产环境必须禁用 none 算法。

Payload 段:声明(Claims)

Payload 是自定义 JSON,没有固定字段。但 JWT 规范定义了 7 个标准声明:

声明 全称 含义 示例
iss Issuer 签发者 "https://example.com"
sub Subject 主题(通常是用户 ID) "user:123"
aud Audience 接收方 "api.example.com"
exp Expiration 过期时间戳(秒) 1761800000
nbf Not Before 生效前时间戳 1761796400
iat Issued At 签发时间戳 1761796400
jti JWT ID 唯一标识(防重放) "a1b2c3d4"

坑 1:exp 是 Unix 时间戳(秒),不是毫秒。很多人看到 10 位数字以为是毫秒就除以 1000,结果把过期时间算成 1970 年了。在线解码工具会自动把时间戳转成人类可读时间(2025-10-30 12:53:20,北京时间)。

坑 2:payload 可以放自定义字段,但敏感信息绝对不能放——payload 是 Base64URL 编码(不是加密),任何人解码就能看到。password、secret、bank_account 这种字段放进去等于公开。

Signature 段:签名校验

Signature = HMACSHA256(header + "." + payload, secret)。

签名校验的坑:

  1. secret 编码问题:某些 JWT 库用 UTF-8 字节做 secret、某些用 Base64 解码后的字节做 secret——同一个 secret 在不同库里签出的 signature 不一样。
  2. 算法不一致:header 写 HS256 但校验时用 RS256,一定校验失败。
  3. "签名校验"和"解码"是两件事:解码永远成功(Base64 解码),但签名校验可能失败。"token 解析成功但 Invalid Signature"是常见报错。

用在线解码工具验证

JWT 在线解码 功能:

  1. 自动解码三段:header / payload 的 JSON 格式化展示,signature 保持原始字符串(不解析)
  2. 过期时间实时提示:exp / iat / nbf 自动换算成本地时间,exp 还会直接标注"剩余 XX"或"已过期"
  3. 不做签名校验:工具不接触 secret——把密钥贴进任何第三方页面都有泄露风险,校验请用 jwt.io 或本地库完成

常见坑

  • "我的 JWT 解码后为什么是乱码":payload 不是 JSON 而是纯文本,或解码用了标准 Base64 而不是 Base64URL。
  • "解码成功但接口返回 401":签名校验失败(secret 错了、算法不一致、token 过期)。
  • "两个人解码同一个 token 得到不同的 JSON 顺序":JSON 键顺序不影响含义,但某些库严格比对字符串时会触发问题。不要把解码后的 JSON 字符串用于比对,用 JSON 解析器比对对象。
  • "为什么不能用 JWT 做会话":JWT 是无状态的(服务器不存),一旦签发就没法撤销。需要"强制下线"场景用 Session + Redis,或 JWT 加黑名单。

相关工具