JWT 还没过期,为什么提示签名验证失败?
签名失败是密码学环节没过,跟过期是两件事——报错里出现断言名,说明签名其实是好的。
签名验证失败和「过期」是两个阶段的错误。签名失败说明密码学这一关就没过,压根还没轮到检查过期时间。
最常见的原因有六类:密钥不对(两端用的密钥不同)、公私钥用反(非对称算法必须用公钥验签)、同一个密钥的编码理解不同(一边当 base64 解码、一边当原文)、算法不匹配、载荷被改动过(哪怕只是重排了 JSON 键顺序),以及 token 在传递中被截断或插入换行。
JWT 是「头、载荷、签名」三段用点号连起来的字符串。前两段只是 Base64URL 编码,任何人解开都能看到内容——它保证的是完整性,不是保密性。签名段则是对前两段字节串做一次带密钥的运算,验证方重算一遍,对得上才放行。
所以「签名验证失败」这句话的含义其实很窄:验证方算出来的结果和签名段不一致。原因必然落在这三样东西之一——签名的输入、用的密钥、用的算法。把它当成三个排查方向,问题就好定位了。
1三段结构,以及签名到底覆盖了什么
先看清签名保护的边界,很多误判都出在这里。
| 段 | 内容 | 是否加密 | 能否被改 |
|---|---|---|---|
| 头 | 算法、类型,可能带密钥编号 | 否,仅 Base64URL | 改了签名就失效 |
| 载荷 | 业务断言:主体、过期时间、签发方等 | 否,仅 Base64URL | 改了签名就失效 |
| 签名 | 对前两段的运算结果 | 否 | 改动同样导致校验失败 |
载荷能被任何人读到,所以绝对不要往里放密码、证件号之类的敏感信息。
2六类根因,按命中率排序
每一类都对应一个具体的、可立即执行的检查动作。
- 密钥不一致
- 签名端和验证端用的密钥不是同一个。特别注意配置值末尾的空格和换行,肉眼看不出来但确实是另一个密钥。
- 公私钥用反
- 非对称算法签名用私钥,验证必须用公钥或密钥集合里的证书。用私钥或不匹配的公钥去验,一定失败。
- 密钥的编码理解不同
- HMAC 的密钥是字节。签名端把配置串按 base64 解码后再用,验证端却按原文使用,双方看起来用的是同一个密钥,签名依然对不上。从配置界面复制的密钥最容易踩这个坑。
- 算法不匹配
- 验证方配置接受的是另一种算法。正确做法是把允许的算法写成固定白名单,而不是听信 token 头里的声明。
- 载荷被动过
- 任何修改,包括把 JSON 重新序列化、调整键顺序、增删空白,都会改变被签名的字节。改完再编码,签名必然失效。
- 传递过程损坏
- 被字段长度截断、复制粘贴时插入换行、认证前缀后多一个空格,或中途被 URL 编码过一次。这类问题通常直接报格式错误,不用查密钥。
最后一类最容易被忽略,也最容易排除:先数一下点号,确认是三段且没有被空格污染,能排掉相当一部分「看起来像签名问题」的情况。
3按顺序排查
从最便宜的检查开始,每一步都能独立排除一批原因。
- 先数点号:确认是标准的三段结构,且没有被换行或空格污染。
- 解开头和载荷,看清里面用的算法和密钥编号到底是什么,同时确认没有混入敏感信息。
- 把算法和自己配置里允许的列表对一遍,不一致就是配置问题,不必继续查密钥。
- 核对密钥:对称算法直接比对两端的原始字节;非对称算法检查密钥编号能否在密钥集合里找到对应公钥,找不到就先刷新一次缓存再重试。
- 让服务器时间持续校准,并给验证库设置 10 到 30 秒的时钟容差,覆盖网络与时钟偏差。
- 最后区分错误类型:报错里点名了过期时间、生效时间或受众,说明签名已经通过,应该去查断言而不是去查密钥。
相关疑问
不校验签名,只看载荷里的角色,行不行?
绝对不行。载荷是明文且可以随意伪造,任何人都能写一个管理员角色进去。签名验证是唯一能证明这段内容来自可信签发方的环节,不能省。
为什么同一份 token 在本地能用,上了生产就失败?
通常是环境差异:签发方、受众、密钥集合、允许的算法、服务器时间,任意一项不同都会失败。按这五项逐一对比两套环境即可。
无签名的 token 是不是可以直接接受?
不可以,这是明确的攻击手法。验证方必须固定自己允许的算法列表,遇到无签名声明直接拒绝。同理,把非对称算法的 token 声明改成对称算法、并用公开的公钥当共享密钥,也是同类攻击。
把生产环境的 token 贴到在线调试工具里安全吗?
不安全。token 等同于凭证,贴出去就等于把访问权交出去。调试时用短期测试 token,或使用本地不上传的工具。
继续看:相关问题与资料
全部问题解答 →内容说明:本页针对具体使用问题作答,方法步骤与数值由本站自行整理与复算,事实性内容以对应官方规范与文档为准。内容最后核对日期:2026-10-08。若发现错误,欢迎通过页脚反馈入口告知。
速查在线工具箱