使用 RestTemplate + BufferingClientHttpRequestFactory 时如何禁用 SSL 证书验证

问题描述

为了与项目的其他部分保持一致,我需要使用 RestTempate,我使用 BufferingClientHttpRequestFactory 因为响应被拦截并注销主体。

我有什么

在 springbootApplication 类中

    @Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
    SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
    RestTemplate template = builder
            .setReadTimeout((int) Duration.ofSeconds(10).toMillis())
            .setConnectTimeout((int)Duration.ofSeconds(10).toMillis())
            .build();
    template.setRequestFactory(new BufferingClientHttpRequestFactory(factory));
    List<ClientHttpRequestInterceptor> interceptorList = new ArrayList<ClientHttpRequestInterceptor>();
    interceptorList.add(new LoggingInterceptor());
    template.setInterceptors(interceptorList);
    return template;}

在服务中

    private ResponseEntity exchangeWithEndpointInternal(RequestEntity<?> request) throws IOException {
    Instant requestStart = this.getClock().instant();
    ResponseEntity response;
    response = restTemplate.exchange(request,String.class);
    Instant requestEnd = this.getClock().instant();
    return response;
}

我的尝试:

覆盖bean定义中的verify方法

        template.setRequestFactory(new BufferingClientHttpRequestFactory(new SimpleClientHttpRequestFactory() {
        @Override
        protected void prepareConnection(HttpURLConnection connection,String httpMethod) throws IOException {
            if (connection instanceof HttpsURLConnection) {
                ((HttpsURLConnection) connection).setHostnameVerifier(new HostnameVerifier() {
                    @Override
                    public boolean verify(String hostname,SSLSession session) {
                            return true;
                        }
                    });
            }

            super.prepareConnection(connection,httpMethod);
        }

    }));

使用 NoopH​​ostVerifier

        template.setRequestFactory(new BufferingClientHttpRequestFactory( new SimpleClientHttpRequestFactory() {
        @Override
        protected void prepareConnection(HttpURLConnection connection,String httpMethod) throws IOException {
            if (connection instanceof HttpsURLConnection) {
                ((HttpsURLConnection) connection).setHostnameVerifier(new NoopHostnameVerifier());
            }
            super.prepareConnection(connection,httpMethod);
        }
    }));

都没有给我我正在寻找的输出,我需要忽略 SSL Validaiton,但我遇到了这个错误

Caused by: org.springframework.web.client.ResourceAccessException: I/O error on POST request for "https://someHost/somePath": PKIX path building Failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target; nested exception is javax.net.ssl.SSLHandshakeException: PKIX path building Failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:742)
at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:635)
at com.....exchangeWithEndpointInternal(FreightapiclientViaHttp.java:97)
at com.....exchangeWithEndpoint(FreightapiclientViaHttp.java:77)
... 73 common frames omitted

有什么想法吗?我很高兴更改工厂,如果我仍然可以多次读取响应正文,这是以前使用 okHttpClient 工作的,没有 RestTemplate,如下所示:

            final TrustManager[] trustAllCerts = new TrustManager[] {
                new x509trustmanager() {
                    @Override
                    public void checkClientTrusted(java.security.cert.X509Certificate[] chain,String authType) throws CertificateException {
                    }

                    @Override
                    public void checkServerTrusted(java.security.cert.X509Certificate[] chain,String authType) throws CertificateException {
                    }

                    @Override
                    public java.security.cert.X509Certificate[] getAcceptedissuers() {
                        return new java.security.cert.X509Certificate[]{};
                    }
                }
        };

        // Install the all-trusting trust manager
        final SSLContext sslContext = SSLContext.getInstance("SSL");
        sslContext.init(null,trustAllCerts,new java.security.SecureRandom());
        // Create an ssl socket factory with our all-trusting manager
        final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();

        OkHttpClient.Builder okHttpClientBuilder = new OkHttpClient.Builder();
        okHttpClientBuilder.sslSocketFactory(sslSocketFactory,(x509trustmanager)trustAllCerts[0]);
        okHttpClientBuilder.hostnameVerifier(new HostnameVerifier() {
            @Override
            public boolean verify(String hostname,SSLSession session) {
                boolean whitelistedDomain = configuration.getSslDomainWhitelist().stream()
                        .peek(String::trim)
                        .filter(domain -> domain.equalsIgnoreCase(hostname))
                        .findAny()
                        .isPresent();
                if (!whitelistedDomain) {
                    return OkHostnameVerifier.INSTANCE.verify(hostname,session);
                } else {
                    return true;
                }
            }
        });

但我无法用其他技术复制行为。

最后一点: 当我使用 curl 触发请求时,出现 SSL 错误,当我添加 -k 标志时,它就很好了。

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)