JWT 还没过期,为什么提示签名验证失败?

3 个讲解板块 · 关联 1 款站内工具 · 内容最后核对 2026-10-08

签名失败是密码学环节没过,跟过期是两件事——报错里出现断言名,说明签名其实是好的。

直接答案

签名验证失败和「过期」是两个阶段的错误。签名失败说明密码学这一关就没过,压根还没轮到检查过期时间。

最常见的原因有六类:密钥不对(两端用的密钥不同)、公私钥用反(非对称算法必须用公钥验签)、同一个密钥的编码理解不同(一边当 base64 解码、一边当原文)、算法不匹配、载荷被改动过(哪怕只是重排了 JSON 键顺序),以及 token 在传递中被截断或插入换行。

JWT 是「头、载荷、签名」三段用点号连起来的字符串。前两段只是 Base64URL 编码,任何人解开都能看到内容——它保证的是完整性,不是保密性。签名段则是对前两段字节串做一次带密钥的运算,验证方重算一遍,对得上才放行。

所以「签名验证失败」这句话的含义其实很窄:验证方算出来的结果和签名段不一致。原因必然落在这三样东西之一——签名的输入、用的密钥、用的算法。把它当成三个排查方向,问题就好定位了。

1三段结构,以及签名到底覆盖了什么

先看清签名保护的边界,很多误判都出在这里。

段内容是否加密能否被改
头算法、类型,可能带密钥编号否,仅 Base64URL改了签名就失效
载荷业务断言:主体、过期时间、签发方等否,仅 Base64URL改了签名就失效
签名对前两段的运算结果否改动同样导致校验失败

载荷能被任何人读到,所以绝对不要往里放密码、证件号之类的敏感信息。

2六类根因,按命中率排序

每一类都对应一个具体的、可立即执行的检查动作。

密钥不一致
签名端和验证端用的密钥不是同一个。特别注意配置值末尾的空格和换行,肉眼看不出来但确实是另一个密钥。
公私钥用反
非对称算法签名用私钥,验证必须用公钥或密钥集合里的证书。用私钥或不匹配的公钥去验,一定失败。
密钥的编码理解不同
HMAC 的密钥是字节。签名端把配置串按 base64 解码后再用,验证端却按原文使用,双方看起来用的是同一个密钥,签名依然对不上。从配置界面复制的密钥最容易踩这个坑。
算法不匹配
验证方配置接受的是另一种算法。正确做法是把允许的算法写成固定白名单,而不是听信 token 头里的声明。
载荷被动过
任何修改,包括把 JSON 重新序列化、调整键顺序、增删空白,都会改变被签名的字节。改完再编码,签名必然失效。
传递过程损坏
被字段长度截断、复制粘贴时插入换行、认证前缀后多一个空格,或中途被 URL 编码过一次。这类问题通常直接报格式错误,不用查密钥。

最后一类最容易被忽略,也最容易排除:先数一下点号,确认是三段且没有被空格污染,能排掉相当一部分「看起来像签名问题」的情况。

3按顺序排查

从最便宜的检查开始,每一步都能独立排除一批原因。

  1. 先数点号:确认是标准的三段结构,且没有被换行或空格污染。
  2. 解开头和载荷,看清里面用的算法和密钥编号到底是什么,同时确认没有混入敏感信息。
  3. 把算法和自己配置里允许的列表对一遍,不一致就是配置问题,不必继续查密钥。
  4. 核对密钥:对称算法直接比对两端的原始字节;非对称算法检查密钥编号能否在密钥集合里找到对应公钥,找不到就先刷新一次缓存再重试。
  5. 让服务器时间持续校准,并给验证库设置 10 到 30 秒的时钟容差,覆盖网络与时钟偏差。
  6. 最后区分错误类型:报错里点名了过期时间、生效时间或受众,说明签名已经通过,应该去查断言而不是去查密钥。

相关疑问

不校验签名,只看载荷里的角色,行不行?

绝对不行。载荷是明文且可以随意伪造,任何人都能写一个管理员角色进去。签名验证是唯一能证明这段内容来自可信签发方的环节,不能省。

为什么同一份 token 在本地能用,上了生产就失败?

通常是环境差异:签发方、受众、密钥集合、允许的算法、服务器时间,任意一项不同都会失败。按这五项逐一对比两套环境即可。

无签名的 token 是不是可以直接接受?

不可以,这是明确的攻击手法。验证方必须固定自己允许的算法列表,遇到无签名声明直接拒绝。同理,把非对称算法的 token 声明改成对称算法、并用公开的公钥当共享密钥,也是同类攻击。

把生产环境的 token 贴到在线调试工具里安全吗?

不安全。token 等同于凭证,贴出去就等于把访问权交出去。调试时用短期测试 token,或使用本地不上传的工具。

内容标识:本页内容由人工智能辅助生成,并经人工核对与编辑。详见 人工智能生成内容标识说明。
内容说明:本页针对具体使用问题作答,方法步骤与数值由本站自行整理与复算,事实性内容以对应官方规范与文档为准。内容最后核对日期:2026-10-08。若发现错误,欢迎通过页脚反馈入口告知。