You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

升级至Spring Boot 3.1.8(含Spring Security 6.x)和Java 21后OAuth 2.0 Resource Server JWT签名验证失败问题

升级至Spring Boot 3.1.8(含Spring Security 6.x)和Java 21后OAuth 2.0 Resource Server JWT签名验证失败问题

我之前升级到Spring Boot 3.1.x + Java 21的时候也碰到过几乎一模一样的JWT签名验证问题,结合你给出的错误信息(客户端返回invalid_token,后端抛出BadJwtException: Signed JWT rejected: Invalid signature),大概率是以下几个常见原因导致的,咱们一步步来排查:

1. 密钥/证书不匹配或加载异常

这是最常见的原因,一定要先确认资源服务器用的验证密钥,和JWT签发方的签名密钥完全一致:

  • 如果是非对称加密(如RSA):检查公钥格式是不是标准PEM格式?有没有多余的换行、空格或者缺失-----BEGIN PUBLIC KEY-----/-----END PUBLIC KEY-----头尾部?另外Spring Security 6.x对密钥加载的细节有调整,Java 21的加密API对格式要求更严格,推荐显式加载公钥,比如:
    @Bean
    public JwtDecoder jwtDecoder() throws Exception {
        Resource publicKeyResource = new ClassPathResource("jwt-public.key");
        byte[] publicKeyBytes = FileCopyUtils.copyToByteArray(publicKeyResource.getInputStream());
        RSAPublicKey publicKey = (RSAPublicKey) KeyFactory.getInstance("RSA")
                .generatePublic(new X509EncodedKeySpec(publicKeyBytes));
        return NimbusJwtDecoder.withPublicKey(publicKey).build();
    }
    
  • 如果是对称加密(如HS256/HS512):要确保配置的密钥字符串和签发方完全一致,注意Java 21默认字符集可能和旧版本有差异,建议显式用UTF-8编码。另外HS256要求密钥至少256位(32个字符以上),短密钥在新版本里会直接被拒绝,比如配置文件可以这么写:
    spring.security.oauth2.resourceserver.jwt.secret-key=your-256-bit-or-longer-secret-string-here
    

2. JWT算法不匹配

检查JWT的alg头字段和你资源服务器配置的算法是否完全对应:比如签发方用RS256签名,你资源服务器却配置成了HS256,肯定会验签失败。Spring Security 6.x对算法的校验比旧版本严格很多,不会自动兼容不匹配的算法。

你可以先用本地的JWT解析工具(比如离线的命令行工具或者离线解析器)把JWT解码,看alg字段的值是什么,再对应调整资源服务器的配置。比如如果是RS256,就一定要用公钥验签,不能用对称密钥。

3. Java 21加密提供者的变化

Java 21默认的安全加密提供者和旧版本(比如Java 17)有一些差异,部分小众加密算法的实现可能被移除或者默认不启用。如果你的JWT用了非标准算法,或者签发方用了比较特殊的加密方式,建议引入BouncyCastle作为第三方加密提供者:

  • 先在依赖里加(Maven为例):
    <dependency>
        <groupId>org.bouncycastle</groupId>
        <artifactId>bcprov-jdk18on</artifactId>
        <version>1.77</version>
    </dependency>
    
  • 然后在启动类里注册提供者:
    static {
        Security.addProvider(new BouncyCastleProvider());
    }
    

4. Spring Security 6.x的自动配置变更

Spring Boot 3.1.x的JWT自动配置有一些细节调整:比如之前用spring.security.oauth2.resourceserver.jwt.jwk-set-uri配置JWK Set地址时,旧版本会自动匹配所有可用密钥,但新版本默认只会选第一个匹配算法的密钥,可能导致密钥不对应。

这种情况下建议自定义JwtDecoder,显式指定密钥选择策略,比如:

@Bean
public JwtDecoder jwtDecoder(OAuth2ResourceServerProperties properties) throws Exception {
    String jwkSetUri = properties.getJwt().getJwkSetUri();
    return NimbusJwtDecoder.withJwkSetUri(jwkSetUri)
            .jwtProcessorCustomizer(processor -> 
                processor.setJWSKeySelector(JWSAlgorithmFamilyJWSKeySelector.fromJWKSetURL(new URL(jwkSetUri))))
            .build();
}

排查小技巧

开启Spring Security的DEBUG日志,能看到JWT验签的每一步细节,比如加载了哪个密钥、用了什么算法,很容易定位问题:

logging.level.org.springframework.security.oauth2=DEBUG

备注:内容来源于stack exchange,提问作者Roma Kap

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.17 09:34:33