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

Spring Boot集成Pac4J与Keycloak时自签名证书加密异常

问题场景

运行Spring Boot 3.2.1并集成嵌入式Keycloak服务器,使用以下Maven依赖:

<dependency>
    <groupId>org.pac4j</groupId>
    <artifactId>jakartaee-pac4j</artifactId>
    <version>8.0.0</version>
</dependency>
<dependency>
    <groupId>org.pac4j</groupId>
    <artifactId>pac4j-oidc</artifactId>
    <version>6.0.1</version>
</dependency>

无SSL配置时认证流程正常,启用SSL Bundle后:

  • Web应用可正常通过HTTPS访问
  • 本地浏览器能正常访问https://localhost:8888/auth/realms/master/.well-known/openid-configuration
    但Pac4J在认证流程中抛出异常:
org.pac4j.core.exception.TechnicalException: Error getting URL resource
    at org.pac4j.core.resource.SpringResourceHelper.getResourceInputStream(SpringResourceHelper.java:74)
    at org.pac4j.oidc.metadata.OidcOpMetadataResolver.retrieveMetadata(OidcOpMetadataResolver.java:89)
    at org.pac4j.oidc.metadata.OidcOpMetadataResolver.internalLoad(OidcOpMetadataResolver.java:76)
    at org.pac4j.core.resource.SpringResourceLoader.load(SpringResourceLoader.java:50)
    at org.pac4j.oidc.config.OidcConfiguration.findPkceMethod(OidcConfiguration.java:285)
    at org.pac4j.oidc.redirect.OidcRedirectionActionBuilder.addStateAndNonceParameters(OidcRedirectionActionBuilder.java:115)
    at org.pac4j.oidc.redirect.OidcRedirectionActionBuilder.getRedirectionAction(OidcRedirectionActionBuilder.java:58)
    at org.pac4j.core.client.IndirectClient.getRedirectionAction(IndirectClient.java:136)
    at org.pac4j.core.engine.DefaultSecurityLogic.redirectToIdentityProvider(DefaultSecurityLogic.java:240)
    at org.pac4j.core.engine.DefaultSecurityLogic.perform(DefaultSecurityLogic.java:160)
    at com.ebremer.server.MyCustomSecurityFilter.internalFilter(MyCustomSecurityFilter.java:79)

已配置trustAllCertificates和TrustAllHostnames,问题仍未解决。


解决方案

1. 为Pac4J显式配置信任所有证书的HTTP客户端

Pac4J默认HTTP客户端可能未复用你配置的SSL上下文,需手动绑定自定义客户端:

OidcConfiguration oidcConfig = new OidcConfiguration();
// 填充其他必要配置(clientId、clientSecret等)

// 创建信任所有证书的HTTP客户端
org.pac4j.http.client.HttpClient pac4jHttpClient = new org.pac4j.http.client.HttpClient();
pac4jHttpClient.setSslContext(createTrustAllSslContext());
pac4jHttpClient.setHostnameVerifier((hostname, session) -> true);

// 绑定到OIDC配置
oidcConfig.setHttpClient(pac4jHttpClient);

其中createTrustAllSslContext()实现:

private SSLContext createTrustAllSslContext() throws NoSuchAlgorithmException, KeyManagementException {
    SSLContext sslContext = SSLContext.getInstance("TLS");
    sslContext.init(null, new TrustManager[]{new X509TrustManager() {
        @Override
        public void checkClientTrusted(X509Certificate[] chain, String authType) {}

        @Override
        public void checkServerTrusted(X509Certificate[] chain, String authType) {}

        @Override
        public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; }
    }}, new SecureRandom());
    return sslContext;
}

2. 自定义SpringResourceHelper绕过默认SSL验证

异常来自SpringResourceHelper的资源加载逻辑,可自定义实现替换默认类:

public class CustomSpringResourceHelper extends SpringResourceHelper {
    @Override
    public InputStream getResourceInputStream(String url) throws IOException {
        // 使用信任所有证书的HttpClient获取元数据
        CloseableHttpClient client = HttpClientBuilder.create()
                .setSSLContext(createTrustAllSslContext())
                .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
                .build();
        HttpGet request = new HttpGet(url);
        HttpResponse response = client.execute(request);
        return response.getEntity().getContent();
    }

    private SSLContext createTrustAllSslContext() throws NoSuchAlgorithmException, KeyManagementException {
        // 同上述SSLContext实现
    }
}

然后在OIDC配置中指定使用该助手:

OidcOpMetadataResolver metadataResolver = new OidcOpMetadataResolver();
metadataResolver.setResourceHelper(new CustomSpringResourceHelper());
oidcConfig.setOpMetadataResolver(metadataResolver);

3. 手动指定OIDC元数据跳过自动获取

如果自动加载元数据的问题无法解决,可直接手动注入元数据内容:

OidcOpMetadata metadata = new OidcOpMetadata();
metadata.setAuthorizationEndpoint("https://localhost:8888/auth/realms/master/protocol/openid-connect/auth");
metadata.setTokenEndpoint("https://localhost:8888/auth/realms/master/protocol/openid-connect/token");
metadata.setUserInfoEndpoint("https://localhost:8888/auth/realms/master/protocol/openid-connect/userinfo");
metadata.setJwksUri("https://localhost:8888/auth/realms/master/protocol/openid-connect/certs");
// 按需补充其他元数据字段

oidcConfig.setOpMetadata(metadata);

此方法会跳过Pac4J对元数据URL的请求,直接使用配置的端点信息。

4. 复用Spring Boot SSL Bundle的上下文

尝试将Spring Boot SSL Bundle生成的上下文注入Pac4J组件:

@Autowired
private SSLBundle sslBundle;

// 在OIDC客户端配置中使用
SSLContext sslContext = sslBundle.createSslContext();
org.pac4j.http.client.HttpClient pac4jHttpClient = new org.pac4j.http.client.HttpClient();
pac4jHttpClient.setSslContext(sslContext);
pac4jHttpClient.setHostnameVerifier(sslBundle.getOptions().getHostnameVerifier());

oidcConfig.setHttpClient(pac4jHttpClient);

内容的提问来源于stack exchange,提问作者Erich Bremer

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 21:47:09