升级io.jsonwebtoken至0.11.2后旧JWT无法通过Key解析问题咨询
问题根因
不兼容问题核心是JJWT不同版本对signWith方法传入字符串参数的处理逻辑差异,以及构造Key对象时的参数错误:
- 旧版本
signWith(SignatureAlgorithm, String)方法隐含逻辑:默认将传入的字符串视为Base64编码后的密钥,会自动先做Base64解码,再用解码后的原始字节作为实际签名密钥 - 当前构造
SecretKeySpec的错误逻辑:直接使用secretKeyEncoded.getBytes()作为入参,这是把Base64编码后的字符串的原始字符字节当成了密钥,和旧版本实际使用的签名密钥完全不一致,自然无法解析旧版本生成的JWT
修复方案
构造Key对象时,先对Base64编码的密钥字符串做解码,再生成密钥对象即可兼容旧有已签发的JWT,正确代码如下:
private final String secretKeyEncoded = Base64.getEncoder().encodeToString(secretKey.getBytes()); // 正确构造Key:先解码Base64字符串,再生成SecretKeySpec byte[] decodedKeyBytes = Base64.getDecoder().decode(secretKeyEncoded); Key key = new SecretKeySpec(decodedKeyBytes, SignatureAlgorithm.HS256.getJcaName()); // 旧版本生成的JWT现在可以正常解析 Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(originalJWT); // 此时可正常运行 // 新版本签发JWT逻辑不变,生成的新JWT也用同一个Key即可正常解析 final String newJWT = Jwts.builder() .setClaims(claims) .setIssuedAt(now) .setExpiration(validity) .signWith(key, SignatureAlgorithm.HS256) .compact();
额外注意事项
如果旧代码中传入signWith的字符串是未经过Base64编码的原始密钥字符串,那么构造Key时不需要做Base64解码,直接使用原始字符串的字节数组生成SecretKeySpec即可:
// 旧密钥是原始字符串未做Base64编码的场景 Key key = new SecretKeySpec(originalSecretStr.getBytes(StandardCharsets.UTF_8), SignatureAlgorithm.HS256.getJcaName());
内容的提问来源于stack exchange,提问作者UnnameDSoS
相关产品推荐
相关产品推荐

