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

Spring Boot OAuth 2授权服务器多实例下JWK值不一致导致资源服务器JWT验证失败

问题分析与解决方案

你遇到的跨实例JWT验证失败问题,核心原因非常清晰:每个授权服务器实例都在维护独立的JWK(JSON Web Key)集合,而且密钥ID(kid)是随机生成的。当资源服务器的请求路由到非签发该JWT的实例时,该实例的JWK集合里找不到对应令牌的kid,自然就会抛出Failed to authenticate since the JWT was invalid错误。

具体代码问题点

看你的generateRsa()方法,每次实例启动都会生成一个全新的随机keyID(UUID.randomUUID().toString()),而且每个实例的JWKSet只包含自身加载的RSA密钥(虽然公私钥来自配置文件,但kid不统一)。资源服务器会从授权服务器的/.well-known/jwks.json端点拉取JWK来验证JWT签名,不同实例返回的JWK集kid不一致,就导致了跨实例验证失败。

修复步骤

1. 固定密钥ID(kid)

不要使用随机UUID生成kid,改为从配置文件读取固定值,或者硬编码一个统一的kid(配置文件方式更灵活)。这样所有实例的JWK中的kid完全一致,资源服务器拿到的JWK集就能匹配令牌中的kid。

修改后的代码示例:

// 从配置文件注入固定的key-id,比如在application.yml中配置 jwt.key-id=my-oauth2-server-kid
@Value("${jwt.key-id}")
private String fixedKeyId;

@Bean
public JWKSource<SecurityContext> jwkSource() {
    RSAKey rsaKey = generateRsa();
    JWKSet jwkSet = new JWKSet(rsaKey);
    return (jwkSelector, securityContext) -> jwkSelector.select(jwkSet);
}

private RSAKey generateRsa() {
    RSAPublicKey publicKey = RsaKeyProperties.getPublicKey();
    RSAPrivateKey privateKey = RsaKeyProperties.getPrivateKey();
    return new RSAKey.Builder(publicKey)
            .privateKey(privateKey)
            .keyID(fixedKeyId) // 使用固定keyId,替代随机UUID
            .build();
}

2. 确保所有实例使用相同的公私钥对

既然你已经自定义了RSA密钥,必须保证所有授权服务器实例加载的是完全相同的公私钥文件/配置。如果公私钥本身不一致,即使kid统一,签名验证也会失败。

3. 验证JWK端点一致性

部署完成后,分别访问每个授权服务器实例的/.well-known/jwks.json端点,检查返回的JWK集合内容是否完全一致(包括kid、公钥参数等)。如果所有实例返回的JWK集相同,说明配置生效了。

额外建议

你当前使用的spring-security-oauth2-authorization-server版本是0.3.1,这是一个较早的预览版本。建议升级到最新的稳定版(比如1.x系列),新版本不仅修复了大量bug,还提供了更完善的集群部署支持,能避免一些潜在的兼容性问题。

另外,你提到会话存储使用Redis,这部分配置是没问题的,它和JWK的跨实例一致性问题无关,不用调整。

内容的提问来源于stack exchange,提问作者Pradeep N S

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.27 17:57:42