JWT Token 解析失败 invalid signature 错误码 401 怎么修复?

文章导读
JWT 出现 invalid signature 伴随 401 错误,本质是服务端校验签名时计算出的哈希值与 Token 携带的签名不一致。这通常由密钥不匹配、算法配置错误或密钥格式问题引起。排查时优先核对签发与校验端的密钥字符串及算法声明。
📋 目录
  1. 核心原因与排查思路
  2. 主流框架配置示例
  3. 密钥生成与管理最佳实践
  4. 调试与验证方法
  5. 常见坑与解决方案
  6. 参考来源
A A

JWT 出现 invalid signature 伴随 401 错误,本质是服务端校验签名时计算出的哈希值与 Token 携带的签名不一致。这通常由密钥不匹配、算法配置错误或密钥格式问题引起。排查时优先核对签发与校验端的密钥字符串及算法声明。

核心结论:绝大多数情况是密钥不一致或算法不匹配,需统一签发与校验端的配置。

  • 确认密钥:签发方与接收方使用的 Secret 或私钥文件内容必须完全一致(包括无多余空格/换行)
  • 核对算法:检查 JWT Header 中的 alg 字段(如 HS256)与后端校验配置是否一致
  • 验证修复:使用新生成的 Token 请求接口,确认 401 错误消失且日志无 signature verification failed

核心原因与排查思路

JWT 由 Header、Payload、Signature 三部分组成。Signature 是通过对 Header 和 Payload 进行哈希运算,并使用密钥签名生成的。服务端收到 Token 后,会用同样的密钥和算法重新计算签名。如果密钥不同、算法不同,或者 Token 在传输中被修改,计算出的签名就会不一致。

排查步骤:

  1. 检查密钥配置:确认签发 Token 的服务和校验 Token 的网关或后端服务,配置的 Secret Key 或私钥文件是否完全一致。
  2. 核对签名算法:查看 Token Header 中的 alg 字段。确保后端校验库配置的算法与此一致。例如,签发用 HS256,校验不能配置为 RS256。
  3. 检查代码实现:确保编码格式统一(通常为 UTF-8),且没有在签名前对字符串进行意外的 trim 或转义。

主流框架配置示例

不同框架对密钥和算法的配置方式不同,以下是常见环境的正确配置参考。

1. Node.js (jsonwebtoken 库)

确保签发与校验使用相同的 secret 和 algorithm 配置。

const jwt = require('jsonwebtoken');
const secret = process.env.JWT_SECRET;

// 签发
const token = jwt.sign({ userId: 1 }, secret, { algorithm: 'HS256', expiresIn: '1h' });

// 校验
try {
  const decoded = jwt.verify(token, secret, { algorithms: ['HS256'] });
} catch (err) {
  // 捕获 InvalidSignatureError
  console.error(err.message);
}

2. Java (Spring Security 6+)

使用 SecretKey 配置 HS256 算法,确保密钥字节一致。

@Bean
public JwtEncoder jwtEncoder() {
    byte[] secretKeyBytes = System.getenv("JWT_SECRET").getBytes(StandardCharsets.UTF_8);
    SecretKey key = new SecretKeySpec(secretKeyBytes, SignatureAlgorithm.HS256.getJcaName());
    return new NimbusJwtEncoder(new ImmutableSecret<>(key));
}

@Bean
public JwtDecoder jwtDecoder() {
    byte[] secretKeyBytes = System.getenv("JWT_SECRET").getBytes(StandardCharsets.UTF_8);
    SecretKey key = new SecretKeySpec(secretKeyBytes, SignatureAlgorithm.HS256.getJcaName());
    return NimbusJwtDecoder.withSecretKey(key).build();
}

密钥生成与管理最佳实践

密钥不一致常源于生成方式随意或存储时混入不可见字符。

1. HS256 密钥生成

使用 OpenSSL 生成随机字符串,避免手动输入。

openssl rand -base64 32

2. RS256 密钥对生成

非对称算法需生成私钥用于签发,公钥用于校验。

openssl genpkey -algorithm RSA -out private_key.pem -pkeyopt rsa_keygen_bits:2048
openssl rsa -pubout -in private_key.pem -out public_key.pem

3. 存储注意事项

JWT Token 解析失败 invalid signature 错误码 401 怎么修复?
  • 环境变量:读取环境变量时,注意去除首尾空格和换行符(如 Docker 挂载文件可能带入换行)。
  • 配置文件:避免将密钥硬编码在代码中,建议使用配置中心或密钥管理服务。
  • 复制粘贴:从文档复制密钥时,检查是否混入了不可见字符。

调试与验证方法

修复配置后,需验证 Token 是否可被正确解析。

1. 使用在线工具解码

推荐使用 jwt.io 调试器。将 Token 粘贴到左侧,右侧输入相同的 Secret 密钥。如果签名验证通过(Verified 绿色),说明密钥和算法匹配;如果显示 Invalid Signature,则说明密钥不一致。

2. 命令行请求测试

使用 curl 携带 Token 请求受保护接口,观察 HTTP 状态码。

curl -H "Authorization: Bearer <your_token>" https://your-api.com/protected

若返回 200 OK 或业务数据,说明签名验证通过。同时观察服务端日志,确认不再有 signature verification failed 类似的错误日志。

常见坑与解决方案

1. 密钥包含不可见字符

从环境变量或文件读取密钥时,可能混入换行符(\n)或空格。建议在代码中读取后执行 trim 操作,或使用 hex 查看密钥实际字节。

2. 算法混淆 (HS256 vs RS256)

HS256 使用对称密钥(同一个 Secret),RS256 使用非对称密钥对(私钥签发,公钥校验)。混淆两者会导致验证永远失败。检查代码中是否错误地将公钥当作 Secret 传入 HS256 算法。

3. 时间戳偏差 (Clock Skew)

如果 Token 刚签发生效即报错,可能是服务器时间不同步。校验端可配置允许的时钟偏差(如 60 秒)。

4. 库版本差异

不同版本的 JWT 库对算法字符串的大小写或默认行为可能有细微差异,升级库时需留意变更日志,明确指定 algorithms 数组。

参考来源

  • RFC 7519: JSON Web Token (JWT) - https://www.rfc-editor.org/rfc/rfc7519.txt
  • JWT.io Introduction - https://jwt.io/
  • Spring Security OAuth2 Resource Server - https://docs.spring.io/spring-security/reference/servlet/oauth2/resource-server/index.html