spring boot 使用RestTemplate通过证书认证访问https实现SSL请求

前面文章有讲过 spring boot 使用RestTemplate信任所有https请求,但实际生产使用时毕竟违反规范使用,造成安全问题,

这里就分享一下通过服务方提供的认证证书来实现https请求;

一、证书转换

1、服务方给的证书多为"cer"类型,比如直接从浏览器中下载下来的,该类证书不能直接使用java调用认证,需转换为java可识别的类型,比如".keystore";

2、利用jdk中"keytool"命令进行转换,即证书导入,windows系统在证书目录打开cmd,执行命令:

   keytool -importcert -keystore client_trust.keystore -file D:\cer\server.cer -alias client_trust_server -storepass 111111 -noprompt

注意:切记“-storepass”后输入的密码,后面要用

参数说明

  • importcert 表示导入信任证书
  • file 指示导入证书,支持pem/der格式
  • keystore 指示目标keystore文件
  • storepass 指示新的keystore密钥
  • alias 指示trust证书在keystore中的别名
  • noprompt 指示不弹出提示

导入后的证书为 trustedCertEntry 实体类型,而私钥证书为 PrivateKeyEntry

二、Spring Boot项目中导入证书

在“resources”目录下新建文件夹“keystore”,并将转换后的证书导入进来:

三、 主要依赖

<!-- SpringBoot版本-->
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.3.4.RELEASE</version>
    <relativePath/>
</parent>

<!-- 主要依赖-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
	<groupId>org.apache.httpcomponents</groupId>
	<artifactId>httpclient</artifactId>
	<version>4.5.13</version>
</dependency>

四、配置RestTemplate实例

import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.ssl.SSLContexts;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.ResourceLoader;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.ResponseErrorHandler;
import org.springframework.web.client.RestTemplate;

import javax.net.ssl.SSLContext;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyStore;

/**
 * RestTemplate - https证书认证
 */
@Configuration
public class RestTemplateOfCerConfig {

    /**
     * resources 目录下证书路径
     * cerPath = "classpath:/keystore/client_trust.keystore";
     */
    @Value("${cer-path}")
    private String cerPath;

    /**
     * 使用"keytool"命令导入证书时输入的密码
     * cerPwd = "111111";
     */
    @Value("${cer-pwd}")
    private String cerPwd;

    @Bean(name = "cerRestTemplate")
    public RestTemplate hwRestTemplate(HttpComponentsClientHttpRequestFactory cerHttpsFactory) {
        RestTemplate restTemplate = new RestTemplate(cerHttpsFactory);
        restTemplate.setErrorHandler(new ResponseErrorHandler() {
            @Override
            public boolean hasError(ClientHttpResponse clientHttpResponse) {
                return false;
            }

            @Override
            public void handleError(ClientHttpResponse clientHttpResponse) {
                //默认处理非200的返回,会抛异常
            }
        });
        return restTemplate;
    }

    @Bean(name = "cerHttpsFactory")
    public HttpComponentsClientHttpRequestFactory httpComponentsClientHttpRequestFactory() throws Exception {
        CloseableHttpClient httpClient = createCloseableHttpClient();
        HttpComponentsClientHttpRequestFactory httpsFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
        httpsFactory.setReadTimeout(2000);
        httpsFactory.setConnectTimeout(2000);
        return httpsFactory;
    }

    /**
     * https协议证书认证
     *
     * @return
     * @throws Exception
     */
    private CloseableHttpClient createCloseableHttpClient() throws Exception {
        KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
        keyStore.load(resourceLoader(cerPath), cerPwd.toCharArray());
        SSLContext sslContext = SSLContexts.custom()
                .loadTrustMaterial(keyStore, new TrustSelfSignedStrategy()).build();
        // 这里的通信协议要根据使用的JDK版本来适配
        SSLConnectionSocketFactory sslfactory = new SSLConnectionSocketFactory(sslContext, new String[]{"TLSv1.2"}, null, NoopHostnameVerifier.INSTANCE);
        HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
        CloseableHttpClient closeableHttpClient = httpClientBuilder.setSSLSocketFactory(sslfactory).build();
        return closeableHttpClient;
    }

    /**
     * 读取文件信息
     *
     * @param fileFullPath
     * @return
     * @throws IOException
     */
    public InputStream resourceLoader(String fileFullPath) throws IOException {
        ResourceLoader resourceLoader = new DefaultResourceLoader();
        return resourceLoader.getResource(fileFullPath).getInputStream();
    }

}

五、JDK版本与通信协议对照

如果你的JDK版本是1.8的,通过上面的配置已可以实现https的SSL请求,但如果你的JDK版本低于1.8,可能就要报错了,

原因是JDK版本与通信协议不一致,具体的版本对照如下图:

找到对应的协议后只需修改以下配置即可:

六、RestTemplate Bean注入

使用时将以上“RestTemplate ”实例注入,此时可实现指定"https"地址的请求,

与通常我们使用“RestTemplate ”调用各种类型的请求方法一样,

RestTemplate ”的通用工具类可参照(文章最后一段): spring boot 使用RestTemplate信任所有https请求

 

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值