项目场景:

springboot 项目作为客户端请求服务端接口,为了保证请求安全,需要采用https双向认证.使用OkHttpClient加载证书


问题描述

双向认证过程,作为客户端除了需要从服务器端下载服务器的公钥证书进行验证外,还需要把客户端的公钥证书上传到服务器端给服务器端进行验证,等双方都认证成功,开始数据传输.

现客户端有服务器根证书:root.cer
客户端证书:client.pfx


实现步骤:

  1. 登录有openssl工具的服务器(一般Linux系统默认都有此工具)
  2. 利用证书格式转换命令cer转pem格式
    openssl x509 -inform der -in root.cer -out root.pem
  3. 添加根证书(root.pem)至可信任证书库(指客户端服务器)
    3.1 进入证书库:cd /Library/Java/JavaVirtualMachines/jdk1.8.0_301.jdk/Contents/Home/jre/lib/security/ (实际服务器的jvm路径)
    3.2执行导入命令: keytool -import -alias ca -keystore cacerts -file /root/root.pem
  4. 将客户端证书《client.pfx》转成keystore,用程序访问服务地址:
    https://serverip:port/(用实际的服务器IP、端口替换serverip和port,确认能够访问的预期内容)
    4.1 keytool -importkeystore -srckeystore client.pfx -destkeystore client.jks -srcstoretype PKCS12 -deststoretype JKS
    4.2 keytool -importkeystore -srckeystore client.jks -srcstoretype JKS -deststoretype PKCS12 -destkeystore client.keystore
  5. 将client.keystore 加载至java代码,代码如下:

java代码 springboot OkHttpClient加载过程

将client.keystore 放在classpath下
在这里插入图片描述

    private SSLSocketFactory createSSLSocketFactory(TrustManager[] trustAllCerts) {
        SSLSocketFactory ssfFactory = null;
        try {

            // 加载客户端证书
            KeyStore keyStore = KeyStore.getInstance("PKCS12");
            ClassPathResource resource = new ClassPathResource("ssl/client.keystore");

            InputStream keyStoreInputStream = resource.getInputStream();

            keyStore.load(keyStoreInputStream, "YourPassword".toCharArray());

            KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509");
            keyManagerFactory.init(keyStore, "YourPassword".toCharArray());

            TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("SunX509");
            trustManagerFactory.init(keyStore);

            //服务端
            SSLContext sslContext = SSLContext.getInstance("SSL");
            sslContext.init(keyManagerFactory.getKeyManagers(), trustAllCerts, new SecureRandom());

            ssfFactory = sslContext.getSocketFactory();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return ssfFactory;
    }
 okHttpClient = new OkHttpClient.Builder()
                            .connectTimeout(60, TimeUnit.SECONDS)//连接超时 设置
                            .writeTimeout(60, TimeUnit.SECONDS)//写超时
                            .readTimeout(60, TimeUnit.SECONDS)//读超时
                            .sslSocketFactory(createSSLSocketFactory(trustManagers), (X509TrustManager) trustManagers[0]) //支持 ssl证书
                            .hostnameVerifier((hostName, session) -> true) //设置用于确认响应证书适用于 HTTPS 连接请求的主机名的验证程序
                            .retryOnConnectionFailure(true) //连接失败时重试
                            .addInterceptor(logInterceptor) // 添加http日日拦截打印
                            .build();

   private static TrustManager[] buildTrustManagers() {
        return new TrustManager[]{
                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[]{};
                    }
                }
        };
    }

证书加载完成,正常调用即可.

补充Spring Boot应用程序中加载资源文件的几种常见方式:

1通过ResourceLoader加载类路径下的资源文件:

@Autowired
private ResourceLoader resourceLoader;

public void loadClasspathResource() {
    Resource resource = resourceLoader.getResource("classpath:ssl/client.keystore");
    // 使用Resource对象读取资源文件内容
}

2.通过ClassPathResource加载类路径下的资源文件:

ClassPathResource resource = new ClassPathResource("ssl/client.keystore");
Logo

技术共进,成长同行——讯飞AI开发者社区

更多推荐