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

Spring WebClient遇中间证书验证失败,寻求非JDK证书安装解决方案

问题分析与解决方案

核心原因

JDK默认信任库(cacerts)未包含USERTrust RSA Certification Authority根CA,而浏览器自带的信任库已内置该CA,因此浏览器访问正常但WebClient调用失败;DFN-Verein Certification Authority 2已在JDK默认信任库中,所以server-02调用无异常。

无需修改JDK全局信任库的解决方案

方案1:为WebClient自定义SSL上下文(推荐,仅影响当前WebClient)

直接在代码中加载目标CA证书(根CA+中间CA),生成专属信任管理器,配置到WebClient中,不影响JVM全局信任设置。

步骤:

  1. 导出USERTrust RSA Certification Authority根CA和GEANT OV RSA CA 4中间CA的证书为PEM格式文件(可从浏览器证书详情导出,或CA官方渠道获取)。
  2. 构建自定义SslContext并配置WebClient:
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.netty.http.client.HttpClient;

import javax.net.ssl.TrustManagerFactory;
import java.io.FileInputStream;
import java.security.KeyStore;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;

// 加载CA证书
List<X509Certificate> caCertificates = new ArrayList<>();
CertificateFactory cf = CertificateFactory.getInstance("X.509");

// 加载根CA证书
try (FileInputStream fisRoot = new FileInputStream("/path/to/USERTrust_RSA_Certification_Authority.pem")) {
    caCertificates.add((X509Certificate) cf.generateCertificate(fisRoot));
}

// 加载中间CA证书
try (FileInputStream fisIntermediate = new FileInputStream("/path/to/GEANT_OV_RSA_CA_4.pem")) {
    caCertificates.add((X509Certificate) cf.generateCertificate(fisIntermediate));
}

// 构建信任库
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
trustStore.load(null);
for (int i = 0; i < caCertificates.size(); i++) {
    X509Certificate cert = caCertificates.get(i);
    trustStore.setCertificateEntry("ca-cert-" + i, cert);
}

// 创建信任管理器工厂
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(trustStore);

// 构建SslContext
SslContext sslContext = SslContextBuilder.forClient()
        .trustManager(tmf)
        .build();

// 配置WebClient
HttpClient httpClient = HttpClient.create().secure(sslSpec -> sslSpec.sslContext(sslContext));
WebClient reactiveWebClient = WebClient.builder()
        .clientConnector(new ReactorClientHttpConnector(httpClient))
        .build();

使用上述自定义的reactiveWebClient调用server-01的API即可正常验证证书。

方案2:通过JVM启动参数指定自定义信任库

创建包含目标CA的独立信任库,启动应用时通过JVM参数指定使用该信任库,无需修改JDK默认cacerts:

  1. 用keytool将CA证书导入自定义信任库:
keytool -importcert -file /path/to/USERTrust_RSA_Certification_Authority.pem -alias usertrust-root -keystore ./custom-truststore.jks -storepass changeit

(若需添加中间CA,重复上述命令导入即可)

  1. 启动应用时添加JVM参数:
java -Djavax.net.ssl.trustStore=./custom-truststore.jks -Djavax.net.ssl.trustStorePassword=changeit -jar your-app.jar

每年更换证书时,仅需更新custom-truststore.jks文件即可。

方案3:排查服务器证书链完整性

虽然你提到openssl验证有效,仍可再次确认server-01是否返回完整证书链:

openssl s_client -connect server-01:443 -showcerts

若输出的证书链缺少GEANT OV RSA CA 4中间CA,需在服务器配置中补充完整证书链(将根CA、中间CA与服务器证书合并为链文件配置),WebClient即可自动获取完整链完成验证。


内容的提问来源于stack exchange,提问作者Thomas Lang

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 08:25:30