Java-HttpClient通过证书实现SSL双向认证(客户端)
Posted 子非衣
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java-HttpClient通过证书实现SSL双向认证(客户端)相关的知识,希望对你有一定的参考价值。
2022-07-25:修复一个bug(javax.net.ssl.SSLPeerUnverifiedException: Certificate for <xx.xxx.xxx.xxx> doesn’t match any of the subject)
修改内容如下:
SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(
sslContext,
NoopHostnameVerifier.INSTANCE);
最近接到一个需求,需要将我们的数据推送到第三方服务器,因此需要用到SSL双向认证,中间查找了一些资料发现都不是很完善,所以综合其他人的一些资料整理了一份。
首先是第三方提供的根证书和客户端秘钥:
根证书:ca.crt
客户端秘钥:client.p12
客户端证书密码:123456
第一步:用根证书生成信任库文件
将根证书ca.crt复制到jdk的jre\\lib\\security目录下(如:C:\\Program Files\\Java\\jdk1.8.0_91\\jre\\lib\\security)
打开电脑CMD命令窗口执行下面命令(这里使用的是jdk自带keytool工具)
test.truststore、DemoCA和密码123456都是自定义的,这个密码需要记住后面加载证书要用到
keytool -keystore test.truststore -keypass 123456 -storepass 123456 -alias DemoCA -import -trustcacerts -file ca.cer
最终在security目录下会生成一个test.truststore文件
第二步:处理HttpClient加载证书
这里直接上代码
因为我这边只需要向第三方推送数据和上传文件所以只写了两个post请求方法
import org.apache.http.HttpEntity;
import org.apache.http.HttpStatus;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.UnknownHostException;
import java.nio.charset.Charset;
import java.security.*;
import java.security.cert.CertificateException;
import java.util.Map;
/**
* Sakura
*/
public class SSLHttpClientUtil
// 客户端证书路径,用了本地绝对路径,需要修改
private final static String CLIENT_CERT_FILE = "E:\\\\Desktop\\\\测试环境通讯SSL双向证书\\\\client.p12";
// 客户端证书密码
private final static String CLIENT_PWD = "123456";
// 信任库路径,即keytool生成的那个自定义名称的库文件
private final static String TRUST_STRORE_FILE = "E:\\\\Desktop\\\\测试环境通讯SSL双向证书\\\\test.truststore";
// 信任库密码,即keytool时的密码
private final static String TRUST_STORE_PWD = "123456";
/**
* 获取HttpClient客户端
*
* @return
*/
public static CloseableHttpClient getHttpClient()
SSLConnectionSocketFactory sslSocketFactory;
try
sslSocketFactory = getSocketFactory();
catch (Exception e)
throw new RuntimeException(e);
CloseableHttpClient httpClient = HttpClientBuilder.create().setSSLSocketFactory(sslSocketFactory).build();
return httpClient;
/**
* 创建SSLSocketFactory实例
*
* @return
* @throws CertificateException
* @throws NoSuchAlgorithmException
* @throws KeyStoreException
* @throws IOException
* @throws KeyManagementException
* @throws UnrecoverableKeyException
*/
private static SSLConnectionSocketFactory getSocketFactory()
throws CertificateException, NoSuchAlgorithmException, KeyStoreException,
IOException, KeyManagementException, UnrecoverableKeyException
// 初始化密钥库
KeyManagerFactory keyManagerFactory = KeyManagerFactory
.getInstance("SunX509");
KeyStore keyStore = getKeyStore(CLIENT_CERT_FILE, CLIENT_PWD, "PKCS12");
keyManagerFactory.init(keyStore, CLIENT_PWD.toCharArray());
// 初始化信任库
KeyStore trustKeyStore = getKeyStore(TRUST_STRORE_FILE, TRUST_STORE_PWD, "JKS");
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(trustKeyStore);
// 加载协议
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null);
//return new SSLConnectionSocketFactory(sslContext);
SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(
sslContext,
NoopHostnameVerifier.INSTANCE);
return sslConnectionSocketFactory;
/**
* 获取(密钥及证书)仓库
*
* @param keyStorePath 证书路径
* @param password 证书密码
* @param type 证书类型
* @return
* @throws KeyStoreException
* @throws CertificateException
* @throws IOException
* @throws NoSuchAlgorithmException
*/
private static KeyStore getKeyStore(String keyStorePath, String password, String type)
throws KeyStoreException, CertificateException, IOException, NoSuchAlgorithmException
// 获取证书
FileInputStream inputStream = new FileInputStream(keyStorePath);
// 秘钥仓库
KeyStore keyStore = KeyStore.getInstance(type);
keyStore.load(inputStream, password.toCharArray());
inputStream.close();
return keyStore;
/**
* post请求发送json格式参数
*
* @param url
* @param strBody
* @return
* @throws Exception
*/
public static String HttpPostByJson(String url, String strBody) throws Exception
CloseableHttpClient httpClient = getHttpClient();
CloseableHttpResponse response = null;
String resultMsg = "";
try
HttpPost httpPost = new HttpPost(url);
httpPost.setHeader("Content-Type", "application/json;charset=UTF-8");
httpPost.setHeader("Accept", "application/json");
StringEntity se = new StringEntity(strBody, Charset.forName("UTF-8"));
se.setContentType("text/json");
httpPost.setEntity(se);
response = httpClient.execute(httpPost);
HttpEntity entity;
entity = response.getEntity();
resultMsg = EntityUtils.toString(entity, "UTF-8");
catch (Exception e)
e.printStackTrace();
finally
try
if (response != null)
response.close();
httpClient.close();
catch (IOException e)
e.printStackTrace();
return resultMsg;
/**
* post请求发送form表单文件及参数
*
* @param url
* @param map
* @param file
* @return
* @throws RuntimeException
*/
public static String sendHttpMessage(String url, Map<String, String> map, File file) throws RuntimeException
CloseableHttpClient httpClient = getHttpClient();
CloseableHttpResponse response = null;
try
if (StringUtils.isEmpty(url) || null == map || map.isEmpty())
return null;
//创建POST请求
HttpPost post = new HttpPost(url);
MultipartEntity entity = new MultipartEntity();
//请求参数
for (String key : map.keySet())
entity.addPart(key, new StringBody(map.get(key), Charset.forName("UTF-8")));
entity.addPart("file", new FileBody(file));
post.setEntity(entity);
response = httpClient.execute(post);
if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK)
throw new RuntimeException("请求失败!");
HttpEntity resEntity = response.getEntity();
return null == resEntity ? "" : EntityUtils.toString(resEntity, "GBK");
catch (UnknownHostException e)
e.printStackTrace();
throw new RuntimeException(e.getMessage());
catch (UnsupportedEncodingException e)
e.printStackTrace();
throw new RuntimeException(e.getMessage());
catch (ClientProtocolException e)
e.printStackTrace();
throw new RuntimeException(e.getMessage());
catch (IOException e)
e.printStackTrace();
throw new RuntimeException(e.getMessage());
catch (Exception e)
e.printStackTrace();
throw new RuntimeException(e.getMessage());
finally
try
if (response != null)
response.close();
httpClient.close();
catch (IOException e)
e.printStackTrace();
/**
* 获取线上文件
* @param destUrl
* @param outputfilePath
*/
public static void saveToFile(String destUrl, String outputfilePath)
FileOutputStream fos = null;
BufferedInputStream bis = null;
HttpURLConnection httpUrl = null;
URL url;
int BUFFER_SIZE = 1024;
byte[] buf = new byte[BUFFER_SIZE];
int size;
try
url = new URL(destUrl);
httpUrl = (HttpURLConnection) url.openConnection();
httpUrl.connect();
bis = new BufferedInputStream(httpUrl.getInputStream());
fos = new FileOutputStream(outputfilePath);
while ((size = bis.read(buf)) != -1)
fos.write(buf, 0, size);
fos.flush();
catch (IOException e)
e.printStackTrace();
throw new RuntimeException(e.getMessage());
catch (ClassCastException e)
e.printStackTrace();
throw new RuntimeException(e.getMessage());
finally
try
fos.close();
bis.close();
httpUrl.disconnect();
catch (IOException e)
catch (NullPointerException e)
第三步:测试方法
public static void main(String[] args) throws Exception
JSONObject json = new JSONObject();
json.put("name", "z3");
String strReturn1 = SSLHttpClientUtil.HttpPostByJson("http://localhost:8230/api", json.toJSONString());
System.out.println(strReturn1);
File temporaryFile = new File("E:\\\\Desktop\\\\图片\\\\123.jpg");
Map<String, String> map = new HashMap<>();
map.put("name", "z3");
map.put("sex", "男");
String strReturn2 = SSLHttpClientUtil.sendHttpMessage("http://localhost:8230/api", map, temporaryFile);
System.out.println(strReturn2);
以上是关于Java-HttpClient通过证书实现SSL双向认证(客户端)的主要内容,如果未能解决你的问题,请参考以下文章