如何在 Spring RestClient 中禁用 SSL 证书校验?
可以通过 RestClient.Builder.requestFactory(...) 配置底层 HTTPS 连接,跳过证书信任校验。RestClient 的 SSL 配置由底层 HTTP 客户端处理,具体方式取决于所用的请求工厂。Spring API 文档
长期访问自签名证书服务时,应让客户端信任该证书。临时联调可以使用下面的配置跳过校验,但这样无法验证服务端证书是否可信,只适合受控的本地测试环境。
使用自定义请求工厂
可以使用 SimpleClientHttpRequestFactory,覆盖其 prepareConnection(...) 方法,为 HTTPS 连接设置自定义 SSLSocketFactory,无需额外的 HTTP 客户端依赖。该方法用于在发送请求前准备连接。Spring 请求工厂文档
以下配置沿用问题中已经能够注入的 RestClient.Builder,可替换原有 Bean 定义。它仅在启用 local profile 时生效:
import java.io.IOException;
import java.net.HttpURLConnection;
import java.security.GeneralSecurityException;
import java.security.cert.X509Certificate;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.web.client.RestClient;
@Configuration
@Profile("local")
public class LocalRestClientConfig {
@Bean
RestClient restClient(RestClient.Builder builder)
throws GeneralSecurityException {
X509TrustManager trustAll = 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];
}
};
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, new TrustManager[] { trustAll }, null);
SSLSocketFactory socketFactory = sslContext.getSocketFactory();
SimpleClientHttpRequestFactory requestFactory =
new SimpleClientHttpRequestFactory() {
@Override
protected void prepareConnection(
HttpURLConnection connection,
String httpMethod) throws IOException {
super.prepareConnection(connection, httpMethod);
if (connection instanceof HttpsURLConnection https) {
https.setSSLSocketFactory(socketFactory);
// 仅在本地测试还需要忽略主机名不匹配时启用:
// https.setHostnameVerifier((hostname, session) -> true);
}
}
};
return builder.requestFactory(requestFactory).build();
}
}
X509TrustManager.checkServerTrusted(...) 负责判断服务端证书链是否可信,示例中的空实现跳过了这项判断。getAcceptedIssuers() 返回空数组本身不会禁用校验。Java X509TrustManager 文档
自签名证书与主机名不匹配要分别处理
证书信任校验与主机名校验检查的是不同内容:
- 证书信任校验判断服务端证书是否可信。上面的自定义 TrustManager 跳过了这一检查。
- 主机名校验判断请求地址中的主机名是否与证书中的身份匹配。上面的代码默认保留这一检查。
如果证书中的名称与请求地址匹配,通常不需要修改 HostnameVerifier。只有在本地测试时遇到名称不匹配,并且确实需要忽略这一问题,才取消示例中 setHostnameVerifier(...) 那一行的注释。
HttpsURLConnection 支持在连接实例上分别设置 SSLSocketFactory 和 HostnameVerifier。示例使用这些实例方法,没有修改 JVM 的全局默认设置。Java HttpsURLConnection 文档
正式环境应配置证书信任
对于需要长期访问的自签名证书服务,可以把经过核实的服务端证书加入专用 truststore;如果服务端证书由内部 CA 签发,则信任对应的 CA。然后使用该 truststore 初始化 TrustManagerFactory,把生成的 TrustManager 传给 SSLContext.init(...),替换示例中的 trustAll,同时保留主机名校验。
示例显式选择了基于 HttpURLConnection 的请求工厂。如果原客户端依赖 Apache HttpClient 等实现的连接池或其他特性,应在原有 HTTP 客户端上配置 TLS,再通过对应的请求工厂接入 RestClient,避免替换后丢失已有行为。
备注:内容仅供参考。
