说明

okhttp是一个用于实现http/https访问的客户端,该文章用来说明如何实现支持https及支持双向认证。

引入

gradle

implementation 'com.squareup.okhttp3:okhttp:4.8.1'

mvaen

<dependency>
	<groupId>com.squareup.okhttp3</groupId>
	<artifactId>okhttp</artifactId>
	<version>4.8.1</version>
</dependency>

代码

//OkhttpUtils.java

import java.io.IOException;
import java.util.UUID;
import javax.net.ssl.HostnameVerifier;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

//平台接口访问工具
public class OkhttpUtils {
    public static boolean isHttps = true;
    public static boolean safetySwitch = true;
    public static boolean certificateIsCA = true;

    //自签名证书关闭验证
    public static HostnameVerifier DO_NOT_VERIFY = (hostname, session) -> true;

    //获取访问前缀
    public static String getHttpOrHttps(){
        return isHttps ? "https://" : "http://";
    }

    //测试https双向访问
    public void httpsTest(){
        OkHttpClient.Builder clientbuilder = new OkHttpClient.Builder();
        if (safetySwitch) clientbuilder.sslSocketFactory(SSLUtils.getCertificates(SSLUtils.getBks(),SSLUtils.getCer()));
        if (certificateIsCA) clientbuilder.hostnameVerifier(DO_NOT_VERIFY);
        OkHttpClient client = clientbuilder.build();

        MultipartBody.Builder builder = new MultipartBody.Builder()
                .setType(MultipartBody.FORM)
                .addFormDataPart("key","value");

        MultipartBody requestBody = builder.build();

        Request request = new Request.Builder()
                .header("Authorization", "Client-ID " + UUID.randomUUID())
                .url(getHttpOrHttps() + "hostname.com/https")
                .post(requestBody)
                .build();

        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                e.printStackTrace();
            }
            @Override
            public void onResponse(Call call, Response response) {
                try {
                    System.out.println(response.body().string());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });
    }
}
//SSLUtils.java

import java.io.*;
import java.security.KeyStore;
import java.security.SecureRandom;
import java.security.cert.CertificateFactory;
import java.util.ArrayList;
import java.util.List;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManagerFactory;

public class SSLUtils {

    ///证书请求文件bks,用于双向认证
    public static InputStream getBks(){
        File file = new File("client_private.bks");
        try {
            InputStream i = new FileInputStream(file);
            return i;
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        return null;
    }

    //证书cer
    public static List<InputStream> getCer(){
        try {
            File file = new File("server_public.cer");
            InputStream i = new FileInputStream(file);
            List<InputStream> publicHers = new ArrayList<>();
            publicHers.add(i);
            return publicHers;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
    
    //获取ssl双向认证的SSLSocketFactory
    public static SSLSocketFactory getCertificates(InputStream privateMe,List<InputStream> publicHers){
        try {
            SSLContext sslContext = SSLContext.getInstance("TLS");

            //远程
            CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
            KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
            keyStore.load(null);
            int index = 0;
            for (InputStream certificate : publicHers)
            {
                String certificateAlias = Integer.toString(index++);
                keyStore.setCertificateEntry(certificateAlias, certificateFactory.generateCertificate(certificate));
                certificate.close();
            }
            TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            trustManagerFactory.init(keyStore);

            //本地
            KeyStore clientKeyStore = KeyStore.getInstance("BKS");
            clientKeyStore.load(privateMe, "123456".toCharArray());
            KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
            keyManagerFactory.init(clientKeyStore, "123456".toCharArray());

            //如何不启用双向认证,则init第一个参数传null即可。
            sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), new SecureRandom());
            return sslContext.getSocketFactory();
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }
    
}