概述
本文是客户端使用httpclient 框架进行通信时的示例,不涉及服务器端的设置
1. 加载证书单向认证
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.SSLContexts;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.File;
import java.io.FileInputStream;
import java.security.KeyStore;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
public class Httpclient43x {
/********************* 4.3.x *****************************/
public void sendMessage() throws Exception {
CloseableHttpClient httpclient = null;
HttpGet httpget = null;
CloseableHttpResponse response = null;
try {
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
FileInputStream instream = new FileInputStream(new File("d:\\tomcat.keystore"));
try {
// 加载keyStore d:\\tomcat.keystore
trustStore.load(instream, "123456".toCharArray());
} catch (CertificateException e) {
e.printStackTrace();
} finally {
try {
instream.close();
} catch (Exception ignore) {
}
}
// 相信自己的CA和所有自签名的证书.SSLContexts 4.3.x之后提供
SSLContext sslcontext = SSLContexts.custom().loadTrustMaterial(trustStore, new TrustSelfSignedStrategy()).build();
// 可选("SSLv3", "TLSv1", "TLSv1.2")
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[]{"TLSv1"}, null,
SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
//设置ssl
httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
// 创建http请求(get方式)
httpget = new HttpGet("https://localhost:8080/test");
response = httpclient.execute(httpget);
HttpEntity entity = response.getEntity();
System.out.println("----------------------------------------");
System.out.println(response.getStatusLine());
if (entity != null) {
System.out.println("Response content length: " + entity.getContentLength());
System.out.println(EntityUtils.toString(entity));
EntityUtils.consume(entity);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (response != null) {
response.close();
}
if (httpget != null) {
httpget.releaseConnection();
}
if (httpclient != null) {
httpclient.close();//等价shutdown
}
}
}
注要步骤就是生成SSLConnectionSocketFactory sslsf
,然后设置到HttpClients
中,这样通过HttpClients获得的http连接
就会带上证书。
单向认证的核心是:在客户端,只设置受信任的公钥信息,不需要设置自己的私钥
2. 忽略证书
与单向认证的区别在于,构建一个空的不携带证书的SSLConnectionSocketFactory sslsf2
,后续步骤基本一致,然后设置到HttpClients
中,这样通过HttpClients获得的http连接
就不会带上证书。
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.SSLContexts;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.File;
import java.io.FileInputStream;
import java.security.KeyStore;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
public class Httpclient43x {
/********************* 4.3.x *****************************/
public void sendMessage() throws Exception {
CloseableHttpClient httpclient = null;
HttpGet httpget = null;
CloseableHttpResponse response = null;
try {
SSLConnectionSocketFactory sslsf2 = new SSLConnectionSocketFactory(ignoreSSL(),
SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
httpclient = HttpClients.custom().setSSLSocketFactory(sslsf2).build(); //空的ssl连接,没有证书信息
// 创建http请求(get方式)
httpget = new HttpGet("https://localhost:8080/test");
response = httpclient.execute(httpget);
HttpEntity entity = response.getEntity();
System.out.println("----------------------------------------");
System.out.println(response.getStatusLine());
if (entity != null) {
System.out.println("Response content length: " + entity.getContentLength());
System.out.println(EntityUtils.toString(entity));
EntityUtils.consume(entity);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (response != null) {
response.close();
}
if (httpget != null) {
httpget.releaseConnection();
}
if (httpclient != null) {
httpclient.close();//等价shutdown
}
}
}
TLS 和ssl区别https://blog.csdn.net/adrian169/article/details/9164385
private static SSLContext ignoreSSL() {
try {
SSLContext sslContext = SSLContext.getInstance("SSLv3");
sslContext.init(null, new TrustManager[]{truseAllManager}, null);
return sslContext;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static TrustManager truseAllManager = new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkServerTrusted(X509Certificate[] arg0, String arg1)
throws CertificateException {
}
public void checkClientTrusted(X509Certificate[] arg0, String arg1)
throws CertificateException {
}
};
}
单向认证的核心是:在客户端,不设置任何证书
3. 双向认证
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.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;
/**
* 4.3版本双向认证
*/
public class HttpTwoWay2 {
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()
//加载服务端提供的truststore(如果服务器提供truststore的话就不用忽略对服务器端证书的校验了)
.loadTrustMaterial(new File("D:\\truststore.jks"), "123456".toCharArray(), new TrustSelfSignedStrategy())
.loadKeyMaterial(keyStore, "cmcc".toCharArray())//loadKeyMaterial()重载方法是加载客户端证书用的
.build();
SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(
sslcontext,
new String[]{"TLSv1"},//new String[]{"SSLv2Hello", "SSLv3", "TLSv1", "TLSv1.2"}
null,
SSLConnectionSocketFactory.getDefaultHostnameVerifier());
CloseableHttpClient httpclient = null;
HttpGet httpget = null;
CloseableHttpResponse response = null;
try {
httpclient = HttpClients.custom().setSSLSocketFactory(sslConnectionSocketFactory).build();
httpget = new HttpGet("https://10.2.5.116/PnsReceiver/ReceiveMessage");
System.out.println("Executing request " + httpget.getRequestLine());
response = httpclient.execute(httpget);
HttpEntity entity = response.getEntity();
System.out.println(response.getStatusLine());
System.out.println(entity.getContent());
EntityUtils.consume(entity);
} finally {
if (response != null) {
response.close();
}
if (httpget != null) {
httpget.releaseConnection();
}
if (httpclient != null) {
httpclient.close();
}
}
}
}
单向认证的核心是:在客户端,既要设置受信任的公钥信息,也需要设置自己的私钥
4. 连接池
参见原文