HttpClient 雙向認證

功能背景

最近我們項目很多依賴API紛紛上Azure,通過Azure的Application Gateway 服務進行負載均衡處理切採用雙向認證。因此我們就需要考慮證書的出示與信任問題,搗鼓了好久,在我差點兒要吐的情況下……還好成功解決了。

角色介紹

  1. 服務器: Azure Gateway
  2. 客戶端: HttpClient

因爲是我們請求Azure Gateway 服務從而請求對應API,所以其就是Server端,相對應的我們就是Client端。

服務器端證書獲取

直接在瀏覽器中訪問Gateway URL ,即可獲取服務器端證書。詳細步驟參考我的文章網站證書獲取

Gateway 信任客戶端證書

好了,到此我們已經有了服務器端的證書,我們可以信任服務器端證書,那麼我們還需要準備我們的證書給Gateway信任,這樣彼此信任方爲雙向認證嘛。^ -^

OpenSSL對d證書文件處理

到目前爲止,我們與Gateway彼此信任,就可以通信了。 但是如果要使用HttpClient還需要一些處理。這裏我們使用OpenSSL(關於OpenSSL有時間我另寫一篇介紹)對證書進行處理。

證書文件生成JKS文件

在OpenSSL中使用下面的命令

Server端證書處理

keytool -import -alias csdncert -keystore trustkeystore.jks -file D:/csdn.cer -storepass changeit

Client端證書處理

Client端證書有一點比較特殊,我們需要使用我們的私鑰。

openssl pkcs12 -export -name myservercert -in myserver.cer –inkey myserver.key -out myserver.p12

證書文件生成P12文件

在OpenSSL中使用下面的命令

Server端證書處理

keytool -importkeystore -destkeystore trustkeystore.jks -srckeystore trustkeystore.p12 -srcstoretype pkcs12 -alias trustkeystore

Client端證書處理

Client端證書有一點比較特殊,我們需要使用我們的私鑰。

keytool -importkeystore -destkeystore myserver.jks -srckeystore myserver.p12 -srcstoretype pkcs12 -alias myserver

HttpClient雙向認證(Mutual Authentication )實現

 public static String doPostJsonWithMutualSSL(String url, String params,String certSystemName) throws Exception{

        RequestConfig config = RequestConfig.custom().setConnectTimeout(3000)
                .setSocketTimeout(3000).build();
        SSLContext sslContext = buildSSLContextForWAS();
        SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(
                sslContext, new String[] { "TLSv1.2", "TLSv1.1", "TLSv1" }, null,
                SSLConnectionSocketFactory.getDefaultHostnameVerifier());
        CloseableHttpClient client = HttpClients.custom().setSSLSocketFactory(sslConnectionSocketFactory)
                .setDefaultRequestConfig(config).build();
        HttpPost httpPost = new HttpPost(url);
        //httpPost.setHeaders(headers);
        httpPost.setHeader("Content-Type", "application/json; charset=utf-8");
        httpPost.setHeader("Accept", "application/json");
        httpPost.setEntity(new StringEntity(params, Charset
                .forName("UTF-8")));
        System.out.println("Access Endpoint: "+ url);
        System.out.println("Request Parameters : "+ params.toString());

        HttpResponse response = client.execute(httpPost);
        HttpEntity responseEntity = response.getEntity();
        String result = EntityUtils.toString(responseEntity, "UTF-8"); // 接口轉碼

        int responseCode = response.getStatusLine().getStatusCode();
        System.out.println("Response Code: "+responseCode);
        System.out.println("Content:-\n"+result);

        return result;
    }
  private static SSLContext buildSSLContextForSystem(){


        FileInputStream identityKeyStoreFile = null;
        FileInputStream trustKeyStoreFile = null;
        SSLContext sslContext = null;
        KeyManagerFactory keyManagerFactory = null;

        try {
            KeyStore identityKeyStore = KeyStore.getInstance("jks");
            identityKeyStoreFile = new FileInputStream("D:\\myserver.jks");
            identityKeyStore.load(identityKeyStoreFile, "changeit".toCharArray());

            KeyStore trustKeyStore = KeyStore.getInstance("jks");
            trustKeyStoreFile = new FileInputStream("D:\\trustkeystore.jks");
            trustKeyStore.load(trustKeyStoreFile, "changeit".toCharArray());


            sslContext = SSLContexts.custom()
                    // load identity keystore
                    .loadKeyMaterial(identityKeyStore, "changeit".toCharArray(), new PrivateKeyStrategy() {
                        @Override
                        public String chooseAlias(Map<String, PrivateKeyDetails> aliases, java.net.Socket socket) {

                            return "csdncert"; //truststore中client證書別名
                        }
                    })
                    // load trust keystore
                    .loadTrustMaterial(trustKeyStore, null)
                    // all trust
                    // .loadTrustMaterial(null, (chain, authType) -> true)
                    .build();
        } catch (Exception ex) {
            System.out.println("build sslContext error:"+ ex);
        } finally {
            try {
                if (identityKeyStoreFile != null) {
                    identityKeyStoreFile.close();
                }
                if (trustKeyStoreFile != null) {
                    trustKeyStoreFile.close();
                }
            } catch (Exception fe) {
                System.out.println("Filestream close error: "+fe);
            }
        }
        return sslContext;
    }

WebSphere中的特殊處理

在WebSphere中對應的keystore爲p12文件,具體路徑可以查看SSL certificate and key management > Key stores and certificates
在這裏插入圖片描述

Gateway server端證書

服務器端證書需要導入DefaultTrustStore,如果是Cluster請導入CellDefaultTrustStore中。
在這裏插入圖片描述

客戶端證書

對於客戶端證書我們可以導入到任意truststore中,我是將其導入到SSL certificate and key management > Key stores and certificates > NodeDefaultTrustStore > Personal certificates

需要私鑰以及client證書生成p12文件,參考上面的client端證書生成p12
在這裏插入圖片描述
在這裏插入圖片描述
這裏的Alias很重要,上面代碼中,loadKeyMaterial中chooseAlias返回的就是這個名稱。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章