文章目錄
功能背景
最近我們項目很多依賴API紛紛上Azure,通過Azure的Application Gateway 服務進行負載均衡處理切採用雙向認證。因此我們就需要考慮證書的出示與信任問題,搗鼓了好久,在我差點兒要吐的情況下……還好成功解決了。
角色介紹
- 服務器: Azure Gateway
- 客戶端: 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返回的就是這個名稱。