错误信息
Error(InvalidSignature)
也可能输出为
- called `Result::unwrap()` on an `Err` value: Error(InvalidSignature)
- InvalidSignature
`{:?}` 打印 `Error(InvalidSignature)`,`{}` 打印 `InvalidSignature`;`.unwrap()` 会 panic,并显示“called `Result::unwrap()` on an `Err` value: Error(InvalidSignature)”。
jsonwebtoken (Rust crate) — ErrorKind::InvalidSignature from decode()
含义
`jsonwebtoken` crate 解析了令牌,接受了其算法,但用你传入的 `DecodingKey` 验证签名没有通过。`Error(InvalidSignature)` 是你在日志和 `unwrap()` panic 中看到的 `Debug` 形式;`Display` 形式只是 `InvalidSignature`。该 crate 不区分“密钥错误”和“令牌被修改”——两者都意味着签名对这个密钥无效。
原因
DecodingKey 不属于签名者
常见来自其他环境的密钥、颁发者轮换密钥后仍在使用的硬编码密钥,或者按位置而不是按 `kid` 选取 JWK。
令牌中的 ECDSA 签名是 DER 编码的
偶见用 KMS 或 OpenSSL 生成的签名手工拼装的令牌,携带的是 DER(约 71 字节),而不是 ES256 要求的 64 字节 r‖s;这样的令牌永远无法通过验证。
HS256 密钥的字节不一致
偶见两端分别使用 `DecodingKey::from_secret(b"...")` 和 `from_base64_secret("...")`,会从同一个配置字符串得到不同的密钥。
修复方法
- 1.
显式处理错误类型
把 `ErrorKind::InvalidSignature` 映射为 401,并与过期区分开,这样客户端就不会反复重试一个永远无法通过验证的令牌。
rust use jsonwebtoken::errors::ErrorKind; match decode::<Claims>(&token, &key, &validation) { Ok(data) => Ok(data.claims), Err(e) => match e.kind() { ErrorKind::InvalidSignature => Err(AuthError::Unauthorized), // wrong key or tampered token ErrorKind::ExpiredSignature => Err(AuthError::Expired), _ => Err(AuthError::BadToken), }, } - 2.
按 kid 从颁发者的 JWKS 中选择密钥
`JwkSet::find` 和 `DecodingKey::from_jwk` 会准确选出颁发者在头部中指定的那个密钥。
rust use jsonwebtoken::{decode_header, jwk::JwkSet, DecodingKey}; let header = decode_header(&token)?; let kid = header.kid.ok_or(AuthError::BadToken)?; let jwk = jwks.find(&kid).ok_or(AuthError::UnknownKey)?; // jwks: JwkSet fetched from the issuer let key = DecodingKey::from_jwk(jwk)?;