重启Spring资源服务器遇Signed JWT rejected错误的解决咨询
解决Spring资源服务器重启时JWT验证错误:"Signed JWT rejected: Another algorithm expected, or no matching key(s) found"
重启Spring资源服务器时触发如下错误:
"Signed JWT rejected: Another algorithm expected, or no matching key(s) found"
该错误来自DefaultJwtProcessor,核心触发代码片段:
JWTClaimsSet claimsSet = extractJWTClaimsSet(signedJWT); List<? extends Key> keyCandidates = selectKeys(signedJWT.getHeader(), claimsSet, context); if (keyCandidates == null || keyCandidates.isEmpty()) { throw new BadJOSEException("Signed JWT rejected: Another algorithm expected, or no matching key(s) found"); }
以下是我按照Spring授权服务器示例实现的配置代码:
授权服务器配置代码
@Bean @Lazy public JWKSource<SecurityContext> jwkSource() { final RSAKey rsaKey = generateRsa(); final JWKSet jwkSet = new JWKSet(rsaKey); return new ImmutableJWKSet<>(jwkSet); } public static RSAKey generateRsa() { final KeyPair keyPair = generateRsaKey(); final RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); final RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); // @formatter:off return new RSAKey.Builder(publicKey) .privateKey(privateKey) .keyID(UUID.randomUUID().toString()) .build(); // @formatter:on } static KeyPair generateRsaKey() { KeyPair keyPair; try { final KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); keyPairGenerator.initialize(2048); keyPair = keyPairGenerator.generateKeyPair(); } catch (Exception ex) { throw new IllegalStateException(ex); } return keyPair; }
资源服务器配置代码
private JwtDecoder jwtDecoder(final String issuerUri) { return NimbusJwtDecoder.withIssuerLocation(issuerUri).jwsAlgorithm(SignatureAlgorithm.RS256).build(); }
问题排查与解决方法
1. 显式指定JWT签名算法
当前授权服务器生成RSA密钥时未明确指定签名算法,可能导致签发JWT时使用的算法与资源服务器配置的RS256不匹配。修改generateRsa()方法,显式添加算法配置:
return new RSAKey.Builder(publicKey) .privateKey(privateKey) .keyID(UUID.randomUUID().toString()) .algorithm(JWSAlgorithm.RS256) // 明确指定RS256算法 .build();
2. 持久化RSA密钥对
你的授权服务器每次启动都会生成新的RSA密钥对,导致重启前签发的JWT用旧密钥签名,重启后资源服务器获取新公钥无法验证旧JWT。解决方式是将密钥对持久化:
- 提前生成RSA密钥对,将公钥、私钥以PEM格式保存到配置文件或数据库
- 修改
generateRsaKey()方法,从持久化存储加载固定密钥,而非每次生成新密钥:
static KeyPair loadRsaKey() { try { // 从配置读取PEM格式的公钥和私钥内容 String publicKeyPem = "你的公钥PEM内容"; String privateKeyPem = "你的私钥PEM内容"; // 解析公钥 String cleanPublicKey = publicKeyPem.replaceAll("-----BEGIN PUBLIC KEY-----", "") .replaceAll("-----END PUBLIC KEY-----", "") .trim(); RSAPublicKey publicKey = (RSAPublicKey) KeyFactory.getInstance("RSA") .generatePublic(new X509EncodedKeySpec(Base64.getDecoder().decode(cleanPublicKey))); // 解析私钥 String cleanPrivateKey = privateKeyPem.replaceAll("-----BEGIN PRIVATE KEY-----", "") .replaceAll("-----END PRIVATE KEY-----", "") .trim(); RSAPrivateKey privateKey = (RSAPrivateKey) KeyFactory.getInstance("RSA") .generatePrivate(new PKCS8EncodedKeySpec(Base64.getDecoder().decode(cleanPrivateKey))); return new KeyPair(publicKey, privateKey); } catch (Exception ex) { throw new IllegalStateException(ex); } }
然后将generateRsa()中的generateRsaKey()替换为loadRsaKey()。
3. 验证JWKS端点返回内容
访问授权服务器的.well-known/jwks.json端点,确认返回的JWK包含:
alg字段值为RS256kid字段与JWT头中的kid一致
确保资源服务器能正确获取到该端点的公钥信息。
4. 调整JwtDecoder构建方式
若上述步骤无效,尝试直接指定JWKS端点构建JwtDecoder:
private JwtDecoder jwtDecoder(final String jwksUri) { // jwksUri示例:http://你的授权服务器地址/oauth2/jwks return NimbusJwtDecoder.withJwkSetUri(jwksUri).jwsAlgorithm(SignatureAlgorithm.RS256).build(); }
内容的提问来源于stack exchange,提问作者user7090887
相关产品推荐
相关产品推荐

