最近要作客戶端和服務器端的雙向認證,在客戶端向服務器端發送帶證書的請求這裏有一點問題,網上的例子大多都不太好使,因而找了github上httpclient源代碼中的例子改造了一下,終於弄明白了java
github上我參考的例子在:https://github.com/apache/httpclient/blob/4.5.x/httpclient/src/examples/org/apache/http/examples/client/ClientCustomSSL.javagit
下面先貼上我本身的代碼(須要導入HttpClient等相關jar包),而後再說明github
import org.apache.commons.io.IOUtils; import org.apache.http.HttpEntity; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.conn.ssl.TrustSelfSignedStrategy; import org.apache.http.conn.ssl.TrustStrategy; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.ssl.SSLContexts; import org.apache.http.util.EntityUtils; import javax.net.ssl.SSLContext; import java.io.File; import java.io.FileInputStream; import java.security.KeyStore; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; /* * Created with Intellij IDEA * USER: 焦一平 * Date: 2016/5/8 * Time: 1:10 * To change this template use File | Settings | File Template */ public class SSLDemo { public static void main(String[] args) throws Exception { KeyStore keyStore = KeyStore.getInstance("PKCS12"); keyStore.load(new FileInputStream(new File("C:\\Users\\Administrator\\Desktop\\jiaoyiping.p12")), "123456".toCharArray()); SSLContext sslcontext = SSLContexts.custom() //忽略掉對服務器端證書的校驗 .loadTrustMaterial(new TrustStrategy() { @Override public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException { return true; } }) //加載服務端提供的truststore(若是服務器提供truststore的話就不用忽略對服務器端證書的校驗了) //.loadTrustMaterial(new File("D:\\truststore.jks"), "123456".toCharArray(), // new TrustSelfSignedStrategy()) .loadKeyMaterial(keyStore, "cmcc".toCharArray()) .build(); SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory( sslcontext, new String[]{"TLSv1"}, null, SSLConnectionSocketFactory.getDefaultHostnameVerifier()); CloseableHttpClient httpclient = HttpClients.custom() .setSSLSocketFactory(sslConnectionSocketFactory) .build(); try { HttpGet httpget = new HttpGet("https://10.2.5.116/PnsReceiver/ReceiveMessage"); System.out.println("Executing request " + httpget.getRequestLine()); CloseableHttpResponse response = httpclient.execute(httpget); try { HttpEntity entity = response.getEntity(); System.out.println(response.getStatusLine()); System.out.println(IOUtils.toString(entity.getContent())); EntityUtils.consume(entity); } finally { response.close(); } } finally { httpclient.close(); } } }
SSLContexts.custom() 方法返回一個 SSLContextBuilder實例,來構建SSLContext,下面是SSLContextBuilder的方法列表:
其中:
loadKeyMaterial()重載方法是加載客戶端證書用的
loadTrustMaterial()重載方法是加載服務器端相關信息用的(咱們就是使用 loadTrustMaterial(TrustStrategy trustStrategy) 方法本身實現了一個信任策略,不對服務器端的證書進行校驗),
在生成HttpClient的時候,指定相應的 SSLSocketFactory,以後,使用這個HttpClient發送的GET請求和POST請求就自動地附加上了證書信息
若是咱們只須要忽略掉對服務器端證書的驗證,而不須要發送客戶端證書信息,在構建SSLContext的時候,只須要 loadTrustMaterial() 不須要 loadKeyMaterial()
關於客戶端證書的類型問題:咱們導出的pfx或者P12後綴的文件都是pkcs12類型的,根據java的文檔,我找到了KeyStore支持的三種類型,以下圖:
客戶端如何只信任某個服務器端的證書信息 會在以後的文章中寫