遇到接口返回 401 时,把 JWT 粘贴进去看到 Payload,只完成了解码;只有用服务端认可的算法和密钥完成验签,并检查时间、签发者和受众等约束,才能判断令牌是否可接受。

先看懂 JWT 的三段结构

常见的签名 JWT 由三段 Base64URL 文本组成,中间用两个英文句点分隔。依据 RFC 7519,JWT 用一组声明表达主体和上下文;签名形式还需要按 JWS 规则验证完整性。

1. Header
eyJhbGciOi...

令牌类型与签名算法等头部参数

2. Payload
eyJzdWIiOi...

sub、exp、aud 等声明,不等于加密内容

3. Signature
SflKxwRJS...

用于校验前两段是否被篡改

Header:算法只是令牌声称的值

Header 常见字段包括 algtyp。解析到 alg: HS256alg: RS256,不代表服务端就应该照单全收;验证端应配置允许的算法,并拒绝不符合预期的算法或密钥类型。

Payload:能看见,不代表可信或保密

Payload 可以被任何拿到令牌的人解码。不要在其中放密码、私钥或无需暴露的个人信息。修改 Payload 后重新编码很容易,但没有正确密钥就无法生成服务端认可的签名。

Signature:验证内容与签发方

签名把编码后的 Header、Payload 与密钥关联起来。HS256 使用共享密钥,签发方和验证方都持有同一秘密;RS256 等非对称算法通常由私钥签发、公钥验证。两者的密钥不能混用。

解码成功不等于验证通过
解码只说明前两段可以还原为数据。即使页面显示了用户名和权限,也必须继续验签并检查声明;未经验证的 Payload 不能作为授权依据。

逐项检查 6 个常见声明

expnbfiat 使用 NumericDate,即从 1970-01-01T00:00:00Z 起计算的秒数。最常见的单位错误是把 JavaScript 的毫秒时间戳直接写进去,导致日期偏离预期。

声明含义排查重点
exp到期时间当前时间达到或超过该 NumericDate 后应拒绝令牌
nbf生效时间当前时间早于该值时,令牌尚不能使用
iat签发时间用于判断令牌年龄,不会单独让令牌自动过期
iss签发者必须与服务端配置的可信签发者一致
aud接收方必须包含当前 API 期望的受众标识
sub主题标识通常标识用户或主体,含义由系统约定
时区通常不是根因,时钟偏差可能是
NumericDate 以 UTC 秒数比较,不依赖界面显示的本地时区。若令牌刚签发就被判定未生效或过期,应检查签发服务器与验证服务器的系统时间;允许多大的时钟偏差应由服务端策略明确配置。

JWT 401 的 5 步排查流程

  1. 1
    保留状态码和响应信息
    记录请求 URL、方法、环境、响应状态和错误体。先确认失败来自目标 API,而不是网关、代理或错误的测试环境。
  2. 2
    核对 Authorization 请求头
    Bearer 与令牌之间应有一个空格;不要带引号、换行,也不要重复拼成 Bearer Bearer ...
  3. 3
    解析结构与时间声明
    把测试令牌放入 JWT 工具,确认恰好有三段,并检查 expnbfissaud
  4. 4
    使用正确密钥验签
    HS 系列填写对应共享密钥;RS、PS、ES 系列使用与签发私钥配对的公钥。不要把公钥当成 HMAC 密钥,也不要只依据 Header 自动选择算法。
  5. 5
    用最小请求复现
    API 调试工具 中只保留必要 Header、参数和请求体,换用专门的测试令牌后再次请求。
实操案例

浏览器登录正常,复制到调试工具却返回 401

开发者从请求面板复制了完整的 Authorization 值,又在调试工具的 Bearer 输入框中手动加了一次前缀;同时令牌的 aud 指向另一个测试 API。
  1. 1.先查看实际发出的请求头,发现值以 Bearer Bearer 开头,删除重复前缀。
  2. 2.解析令牌并核对 exp,确认仍在有效期内,再发现 aud 与当前接口不一致。
  3. 3.从正确环境重新获取测试令牌,用对应公钥验签后发送同一份最小请求。
得到什么:把传输格式错误与令牌声明错误分开定位,不需要反复修改业务请求体或猜测接口故障。

常见现象与对应检查点

  • Invalid signature:检查密钥、算法、密钥轮换后的 kid 和令牌是否被截断;
  • Token expired:比较服务端当前时间与 exp,重新走刷新或登录流程,不要手改 Payload;
  • Token not active:检查 nbf 以及签发端、验证端的系统时钟;
  • Invalid issuer / audience:确认令牌来自当前环境,且 issaud 满足 API 配置;
  • Malformed token:清理引号、空格和换行,确认令牌是完整三段而不是刷新令牌或其他凭证;
  • 验签通过仍被拒绝:继续检查 scope、role、账户状态和接口权限;这类情况有些服务会返回 403,也有实现仍返回 401。

如果接口错误体本身是 JSON 且无法解析,可先按JSON 格式错误排查指南清理响应,再判断认证失败原因。

调试 JWT 时不要泄露真实凭证

Bearer Token 通常等同于一段临时访问权限。即使 JWT 工具在浏览器本地处理并把最近记录保存在本机,也不应把仍有效的生产令牌发到群聊、工单、截图或可分享链接中。

  • 优先使用测试环境、低权限且短时有效的专用令牌;
  • 分享问题时只保留脱敏后的 Header、必要声明和错误信息;
  • 怀疑泄露时立即吊销或轮换相关凭证,不要等待自然过期;
  • 调试完成后清理工具历史、剪贴板、终端记录和截图。
Base64URL 只负责表示数据
JWT 前两段使用 Base64URL 表示内容,它不是加密。需要单独观察编码差异时,可以用 Base64 编解码工具,但最终仍应回到 JWT 验签流程判断可信性。

常见问题

JWT 能解码出来,为什么接口还是返回 401?

解码不检查签名、过期时间、签发者或受众。还要确认 Authorization 格式、用正确密钥验签,并让 expnbfissaud 满足目标 API 的配置。

JWT 的 exp 是秒还是毫秒?

RFC 7519 定义的 NumericDate 使用秒。JavaScript 的 Date.now() 返回毫秒,生成声明时通常需要除以 1000 并取整;读取时则乘以 1000 再构造日期。

只检查 exp,没有过期就可以信任 JWT 吗?

不可以。攻击者可以自行修改 Payload 中的 exp。必须先用允许的算法和可信密钥验证签名,再检查时间、签发者、受众以及业务权限。

HS256 和 RS256 验签有什么区别?

HS256 使用同一个共享密钥签发和验证,持有验证密钥的一方也能签发;RS256 使用私钥签发、公钥验证,验证方不需要拿到私钥。服务端应明确限定算法,不能让令牌自行决定安全策略。

JWT 验签通过,为什么仍然没有接口权限?

验签只证明令牌内容未被篡改且来自对应密钥。API 还可能检查 scope、角色、租户、账户状态和资源归属;这些授权条件不满足时仍会拒绝访问。

可以把 JWT 发给同事帮忙排查吗?

不要发送仍有效的真实令牌。优先创建低权限测试令牌,或只分享脱敏后的 Header、必要声明、状态码和错误信息;若令牌已经外泄,应立即吊销或轮换。

现在可以打开 JWT 工具 解析内置示例,再用API 调试工具 复现一份不含真实凭证的最小请求;也可以回到在线工具集首页 查找其他开发与编码工具。