RestTemplate发送HTTPS请求

RestTemplate发送HTTPS请求

基础知识:

Https原理与工作流程及证书校验:https://www.cnblogs.com/zjdxr-up/p/14359904.html

忽略ssl证书的方式配置:

import lombok.extern.slf4j.Slf4j;

import org.springframework.http.client.SimpleClientHttpRequestFactory;

import java.io.IOException;
import java.net.HttpURLConnection;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
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;

@Slf4j
public class IgnoreCertificateHttpsClientRequestFactory extends SimpleClientHttpRequestFactory {
    @Override
    protected void prepareConnection(HttpURLConnection connection, String httpMethod) throws IOException {
        try {
            // 判断类型是http还是https
            if (!(connection instanceof HttpsURLConnection)) {
                super.prepareConnection(connection, httpMethod);
                return;
            }
            // 强制转换成HttpsURLConnection
            HttpsURLConnection httpsConnection = (HttpsURLConnection) connection;

            // X509TrustManager用于实现SSL证书的安全校验
            X509TrustManager x509m =
                    new X509TrustManager() {
                        // 返回受信任的X509证书数组。
                        @Override
                        public X509Certificate[] getAcceptedIssuers() {
                            log.info("getAcceptedIssuers");
                            return null;
                        }

                        /**
                         * 该方法检查服务器的证书,若不信任该证书同样抛出异常。通过自己实现该方法,可以使之信任我们指定的任何证书。
                         * 在实现该方法时,也可以简单的不做任何处理,即一个空的函数体,由于不会抛出异常,它就会信任任何证书。
                         */
                        @Override
                        public void checkServerTrusted(X509Certificate[] chain, String authType) {
                            log.info("checkServerTrusted");
                        }

                        /**
                         * 该方法检查客户端的证书,若不信任该证书则抛出异常。由于我们不需要对客户端进行认证
                         * 因此我们只需要执行默认的信任管理器的这个方法。Java Secure Socket Extension(JSSE)中,默认的信任管理器类为TrustManager。
                         */
                        @Override
                        public void checkClientTrusted(X509Certificate[] chain, String authType) {
                            log.info("checkClientTrusted");
                        }
                    };
            /**
             * SSLContext的实例表示安全套接字协议实现,它充当安全套接字工厂或SSLEngine的工厂。
             * 该类使用一组可选的密钥和信任管理器以及安全随机字节源进行初始化。
             * 获取一个SSLContext实例对象,并使用我们指定的信任管理器初始化
             */
            SSLContext sslContext = SSLContext.getInstance("SSL");

            /**
             * 初始化SSL环境
             * 第二个参数是告诉JSSE使用的可信任证书的来源,设置为null是从javax.net.ssl.trustStore中获得证书
             * 第三个参数是JSSE生成的随机数,这个参数将影响系统的安全性,设置为null是个好选择,可以保证JSSE的安全性。
             */
            sslContext.init(null, new TrustManager[] {x509m}, new java.security.SecureRandom());
            // 返回此上下文的 SocketFactory对象。
            SSLSocketFactory socketFactory = sslContext.getSocketFactory();
            httpsConnection.setSSLSocketFactory(socketFactory);
            super.prepareConnection(httpsConnection, httpMethod);
        } catch (NoSuchAlgorithmException exception) {
            throw new RuntimeException(exception);
        } catch (KeyManagementException exception) {
            throw new RuntimeException(exception);
        }
    }
}

使用ssl证书的配置:

import lombok.extern.slf4j.Slf4j;

import org.springframework.http.client.SimpleClientHttpRequestFactory;

import java.io.FileInputStream;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManagerFactory;

@Slf4j
public class UsingCertificateHttpsClientRequestFactory extends SimpleClientHttpRequestFactory {
    private String type;
    private String path;
    private String password;

    public UsingCertificateHttpsClientRequestFactory(String type, String path, String password) {
        super();
        this.type = type;
        this.path = path;
        this.password = password;
    }

    @Override
    protected void prepareConnection(HttpURLConnection connection, String httpMethod) throws IOException {
        // 判断类型是http还是https
        try {
            if (!(connection instanceof HttpsURLConnection)) {
                super.prepareConnection(connection, httpMethod);
                return;
            }
            // 强制转换成HttpsURLConnection
            HttpsURLConnection httpsConnection = (HttpsURLConnection) connection;
            // 加载包含受信任证书的本地密钥库
            // 建议使用:KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
            KeyStore keyStore = KeyStore.getInstance(this.type);
            try (FileInputStream inputStream = new FileInputStream(this.path); ) {
                // 使用 keyStore 类将证书库或信任库文件加载进来
                keyStore.load(inputStream, this.password.toCharArray());
                log.info("loading jks ...");
            } catch (CertificateException e) {
                throw new RuntimeException(e);
            }
            // 使用 KeyManagerFactory 和加载了证书库的 Keystore 实例,产生 KeyManager 实例数组
            // 使用 TrustManagerFactory 和加载了信任库的 Keystore 实例,产生 TrustManager 实例数组
            TrustManagerFactory trustManagerFactory =
                    TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            trustManagerFactory.init(keyStore);
            // 使用 SSLContext 初始化 KeyManager 实例数组和 TrustManager 实例数组,从而设定好通信的环境
            SSLContext sslContext = SSLContext.getInstance("SSL");
            sslContext.init(null, trustManagerFactory.getTrustManagers(), new java.security.SecureRandom());
            // 返回此上下文的 SocketFactory对象。
            SSLSocketFactory socketFactory = sslContext.getSocketFactory();
            // 利用 SSLContext 产生的 SSLSocket 或 SSLServerSocket 进行通信
            httpsConnection.setSSLSocketFactory(socketFactory);
            super.prepareConnection(httpsConnection, httpMethod);
        } catch (KeyStoreException exception) {
            throw new RuntimeException(exception);
        } catch (NoSuchAlgorithmException exception) {
            throw new RuntimeException(exception);
        } catch (KeyManagementException exception) {
            throw new RuntimeException(exception);
        }
    }
}

RestTemplate的配置文件RestTemplateConfiguration:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.web.client.RestTemplate;

import java.nio.charset.StandardCharsets;

@Configuration
public class RestTemplateConfiguration {
    @Bean("restTemplate")
    public RestTemplate restTemplate() {
        UsingCertificateHttpsClientRequestFactory factory =
                new UsingCertificateHttpsClientRequestFactory("jks", "D:/truststore.jks", "changeit");
        // 忽略证书方式: IgnoreCertificateHttpsClientRequestFactory factory = new IgnoreCertificateHttpsClientRequestFactory();
        factory.setConnectTimeout(5000);
        factory.setReadTimeout(5000);
        RestTemplate restTemplate = new RestTemplate(factory);
        // 解决中文乱码问题
        restTemplate.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8));
        return restTemplate;
    }
}

你可能感兴趣的:(https,RestTemplate)