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

容器化Spring Boot资源服务器后无法验证OAuth2 Access Token问题

问题描述

我用Spring Boot结合OAuth2保护REST API,依赖配置如下:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-oauth2-jose</artifactId>
</dependency>

application.properties配置:

spring.security.oauth2.resourceserver.jwt.issuer-uri=https://authServer.com/auth/realms/api-dev

授权服务器是容器化部署的Keycloak。非容器化启动资源服务器时,能正常验证客户端Access Token并访问受保护资源;但容器化后,Postman请求返回401错误,容器日志显示连接超时:

org.springframework.security.authentication.AuthenticationServiceException: An error occurred while attempting to decode the Jwt: Couldn't retrieve remote JWK set: org.springframework.web.client.ResourceAccessException: I/O error on GET request for "https://authServer.com/auth/realms/api-dev/protocol/openid-connect/certs": Connection timed out (Connection timed out); nested exception is java.net.ConnectException: Connection timed out (Connection timed out)

Caused by: org.springframework.security.oauth2.jwt.JwtException: An error occurred while attempting to decode the Jwt: Couldn't retrieve remote JWK set: org.springframework.web.client.ResourceAccessException: I/O error on GET request for "https://authServer.com/auth/realms/api-dev/protocol/openid-connect/certs": Connection timed out (Connection timed out); nested exception is java.net.ConnectException: Connection timed out (Connection timed out)
        at org.springframework.security.oauth2.jwt.NimbusJwtDecoder.createJwt(NimbusJwtDecoder.java:169) ~[spring-security-oauth2-jose-5.7.4.jar!/:5.7.4]
        at org.springframework.security.oauth2.jwt.NimbusJwtDecoder.decode(NimbusJwtDecoder.java:137) ~[spring-security-oauth2-jose-5.7.4.jar!/:5.7.4]
        at org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationProvider.getJwt(JwtAuthenticationProvider.java:97) ~[spring-security-oauth2-resource-server-5.7.4.jar!/:5.7.4]
        ... 55 common frames omitted
Caused by: com.nimbusds.jose.RemoteKeySourceException: Couldn't retrieve remote JWK set: org.springframework.web.client.ResourceAccessException: I/O error on GET request for "https://authServer.com/auth/realms/api-dev/protocol/openid-connect/certs": Connection timed out (Connection timed out); nested exception is java.net.ConnectException: Connection timed out (Connection timed out)

需要解决容器化后无法验证Access Token的问题。


解决方案

1. 排查容器网络连通性

  • 进入资源服务器容器内部,执行curl https://authServer.com/auth/realms/api-dev/protocol/openid-connect/certs,确认是否能正常返回JWK集合。如果curl也超时,说明容器到Keycloak的网络存在问题:
    • 若Keycloak和资源服务器在同一Docker网络,改用容器名称或服务名访问,比如http://keycloak-container-name/auth/realms/api-dev(注意如果Keycloak启用HTTPS,需确保容器内信任其证书)。
    • 若Keycloak部署在外部服务器,检查容器所在主机的防火墙、安全组是否允许容器访问Keycloak的443端口;同时确认容器的DNS配置正确,能正常解析authServer.com域名。

2. 配置JWK请求超时与缓存

Spring Security默认的JWK请求未设置合理超时,容器网络环境下容易触发超时。可以自定义JwtDecoder,添加超时配置并启用JWK缓存:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.oauth2.jwt.JwtDecoder;
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.client.RestTemplateBuilder;

import java.time.Duration;

@Configuration
public class JwtConfig {

    @Bean
    public JwtDecoder jwtDecoder() {
        RestTemplate restTemplate = new RestTemplateBuilder()
                .setConnectTimeout(Duration.ofSeconds(10))
                .setReadTimeout(Duration.ofSeconds(10))
                .build();

        NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withIssuerLocation("https://authServer.com/auth/realms/api-dev")
                .restOperations(restTemplate)
                .build();
        
        // 配置JWK缓存,避免频繁请求Keycloak
        jwtDecoder.setJwkSetCache(new org.springframework.security.oauth2.jwt.DefaultJwkSetCache(Duration.ofHours(1)));
        
        return jwtDecoder;
    }
}

3. 处理Keycloak证书信任问题

如果Keycloak使用自签名证书,容器内的JVM默认不会信任该证书,导致连接失败:

  • 将Keycloak的证书导出,添加到资源服务器容器的JVM信任库中,可在Dockerfile中添加以下步骤:
COPY keycloak.crt /tmp/
RUN keytool -importcert -file /tmp/keycloak.crt -alias keycloak -keystore $JAVA_HOME/lib/security/cacerts -storepass changeit -noprompt
  • 或者在启动容器时指定自定义信任库参数:
docker run -e JAVA_OPTS="-Djavax.net.ssl.trustStore=/path/to/truststore.jks -Djavax.net.ssl.trustStorePassword=changeit" your-resource-server-image

4. 验证Keycloak Issuer配置一致性

检查Keycloak Realm的Issuer设置,确保其对外暴露的地址和资源服务器配置的issuer-uri完全一致:

  • 登录Keycloak管理后台,进入目标Realm的Realm Settings → General → Frontend URL,设置为正确的外部访问地址(如https://authServer.com/auth/realms/api-dev),避免JWK响应中的Issuer值与资源服务器配置不匹配。

内容的提问来源于stack exchange,提问作者Severin Mbekou

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 21:25:24