調用第三方服務時,廠商提供了一個WSDL文件、調用的地址和一個后綴為pfx的證書文件,通過SOUPUI記載證書是可以正常調用WebService服務,那么如何將該服務轉換為代碼呢?
咨詢了廠商的支持,廠商說直接發送報文即可。
觀察SOUPUI的調用發現直接發送的SOUP報文,那么決定使用HttpClient進行服務調用,調用HTTPS好說、發送報文也好說,關鍵問題卡在了pfx證書上面。
百度了很多例子,說JAVA無法直接攜帶pfx的證書,那么就在pfx證書轉換方面嘗試了一些,最終沒有轉換成功。
繼續觀察SOUPUI的調用模式,SOUPUI可以在PERFERENCE的SSL中可以直接配置keystore和password,就可以攜帶證書,而且SOUPUI調用各種服務主要是使用HTTPClient完成的的,他可以實現,那就說明通過HTTPClient是可以直接攜帶pfx格式的證書的,基本思路確定,那就全力在這條路上繼續折騰吧。
整理一下尷尬的情況:
資源:HTTPS協議、WebService服務、需要pfx證書認證;
目標:通過HttpClient構建SSL通道調用HTTPS的WebService接口,攜帶pfx證書信息,直接發送SOUP報文調用接口;
難點:pfx證書如何處理?
百度了好久,有相應的解決方案,但實驗后均不行;后在bing的國際版中進行搜索,結果中stackoverflow中有了大收獲。
地址:https://stackoverflow.com/questions/44493040/apache-httpclient-pfx-file
該國際友人碰到了和我一樣的問題,通過SOUPUI攜帶pfx證書調用Https的WebService服務沒有問題,使用HttpClient模擬報文的時候無法攜帶證書,但是該哥們自行解決了該問題,而且還無私的把源代碼整個貼在了論壇上,我用顫抖的雙手復制粘貼了該代碼,稍作修改執行發現問題解決。天哪,折騰了一個下午加晚上,終於算是解決了。
在此特意轉發一下這位大神的佳作:
KeyStore clientStore = KeyStore.getInstance("PKCS12"); InputStream instream = Thread.currentThread().getContextClassLoader().getResourceAsStream(keystoreName); try { clientStore.load(instream, keyStorePwd.toCharArray()); } finally { instream.close(); } //Trust everybody X509TrustManager tm = new X509TrustManager() { @Override public void checkClientTrusted(java.security.cert.X509Certificate[] arg0, String arg1) throws CertificateException {} @Override public void checkServerTrusted(java.security.cert.X509Certificate[] arg0, String arg1) throws CertificateException {} @Override public java.security.cert.X509Certificate[] getAcceptedIssuers() {return null;} }; SSLContext sslCtx = SSLContext.getInstance("TLS"); KeyManagerFactory kmfactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); kmfactory.init(clientStore, keyStorePwd != null ? keyStorePwd.toCharArray() : null); KeyManager[] keymanagers = kmfactory.getKeyManagers(); sslCtx.init(keymanagers, new TrustManager[]{tm}, null); SSLConnectionSocketFactory sslConnectionFactory = new SSLConnectionSocketFactory(sslCtx); Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create().register("https", sslConnectionFactory).register("http", new PlainConnectionSocketFactory()).build(); PoolingHttpClientConnectionManager pcm = new PoolingHttpClientConnectionManager(registry); HttpClientBuilder hcb = HttpClientBuilder.create(); hcb.setConnectionManager(pcm); CloseableHttpClient httpClient = hcb.build();