OkHttpClient在使用JRE信任库的基础上加上自定义证书

发布时间 2023-04-18 14:35:20作者: N!CE波

要在OkHttpClient使用JRE信任库的基础上加上自定义证书,可以使用自定义TrustManager的方式来实现。

首先,需要创建一个X509TrustManager的实现类,这个实现类需要实现checkServerTrusted方法,用于检查服务端返回的证书是否是受信任的证书。在实现checkServerTrusted方法时,可以先调用JRE信任库中的X509TrustManager的checkServerTrusted方法,再加上自定义的检查逻辑,确保返回的证书是受信任的。具体实现如下:

    public static class CustomTrustManager implements X509TrustManager {
        private X509TrustManager defaultTrustManager;
        private X509TrustManager localTrustManager;

        public CustomTrustManager() throws Exception {
            TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            tmf.init((KeyStore) null);
            defaultTrustManager = findX509TrustManager(tmf);
            localTrustManager = createLocalTrustManager();
        }

        @Override
        public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
            throw new UnsupportedOperationException();
        }

        @Override
        public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
            try {
                defaultTrustManager.checkServerTrusted(chain, authType);
            } catch (CertificateException ce) {
                localTrustManager.checkServerTrusted(chain, authType);
            }
        }

        @Override
        public X509Certificate[] getAcceptedIssuers() {
            return defaultTrustManager.getAcceptedIssuers();
        }

        private X509TrustManager findX509TrustManager(TrustManagerFactory tmf) {
            TrustManager[] trustManagers = tmf.getTrustManagers();
            for (TrustManager tm : trustManagers) {
                if (tm instanceof X509TrustManager) {
                    return (X509TrustManager) tm;
                }
            }
            return null;
        }

        private X509TrustManager createLocalTrustManager() throws Exception {
            KeyStore localTrustStore = KeyStore.getInstance(KeyStore.getDefaultType());
            localTrustStore.load(null, null);
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
            Resource resource = ResourcePatternUtils.getResourcePatternResolver(new DefaultResourceLoader()).getResource("/sectigo_root_certificates_1199354.crt");
            InputStream caInput = resource.getInputStream();
            try {
                Certificate ca = cf.generateCertificate(caInput);
                localTrustStore.setCertificateEntry("custom-cert", ca);
            } finally {
                caInput.close();
            }
            TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            tmf.init(localTrustStore);
            return findX509TrustManager(tmf);
        }
    }

在上面的实现中,CustomTrustManager类实现了X509TrustManager接口,并包含了两个X509TrustManager实例:defaultTrustManager和localTrustManager。defaultTrustManager是从JRE信任库中获取的X509TrustManager,localTrustManager是自定义的TrustManager。在checkServerTrusted方法中,先调用defaultTrustManager的checkServerTrusted方法,如果检查不通过,则调用localTrustManager的checkServerTrusted方法进行自定义的检查。

接下来,可以将自定义的TrustManager实例添加到OkHttpClient中:

    public static void main(String[] args) throws Exception {
        CustomTrustManager customTrustManager = new CustomTrustManager();
        // 创建SSLContext
        SSLContext sslContext = Platform.get().getSSLContext();
        sslContext.init(null, new TrustManager[] { customTrustManager }, null);

        // 创建OkHttpClient
        OkHttpClient httpClient = new OkHttpClient.Builder()
                .sslSocketFactory(sslContext.getSocketFactory(), customTrustManager)
                .build();

        final Request request = new Request.Builder().url("https://www.baidu.com").build();
        httpClient.newCall(request).execute();
    }