PAYATHON 2026

如何在 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,避免替换后丢失已有行为。

备注:内容仅供参考。