基于springboot 根据ca.crt、client.crt和client.key文件实现与服务端https通讯
服务端提供了三个文件需要进行TLS方式通讯,三个文件分别为ca.crt、client.crt、client.key:
ca.crt 为服务端证书
client.crt 为服务端分配给客户端的证书
client.key 为服务端分配给客户端证书私钥
三个文件的具体格式说明我就不做赘述了,都可以在网上查到,也不多说废话,直接贴代码:
参考文章
参考文章: https://blog.csdn.net/qq_38417913/article/details/82150186.
pom.xml添加依赖
// pom.xml 添加依赖
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.6</version>
</dependency>
客户端认证代码
// An highlighted block
import com.alibaba.fastjson.JSONObject;
import com.Exception.base.exceptions.BusinessException;
import org.apache.http.HttpEntity;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.stereotype.Component;
import org.springframework.util.StreamUtils;
import sun.misc.BASE64Decoder;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.SecureRandom;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.spec.PKCS8EncodedKeySpec;
/**
* @ClassName CertificateHttpsTools
* @Description 客户端带证书https方式请求服务端
* @Author user
* @Date 2020/6/18 10:23
* @Version 1.0
**/
@Component
public class CertificateHttpsTools {
private static Logger logger = LogManager.getLogger(CertificateHttpsTools.class);
public static final String CA_PATH = "C:/Users/Desktop/cer/ca.crt";
public static final String CRT_PATH = "C:/Users/Desktop/cer/client.crt";
public static final String KEY_PATH = "C:/Users/Desktop/cer/client.key";
public static final String PASSWORD = "123";
public static String httpPost(String url, String jsonParam) throws IOException {
CloseableHttpClient httpClient = null;
String result = null;
logger.info("请求数据:"+jsonParam);
try{
//加载证书
SSLConnectionSocketFactory sslsf = getSSLSocktetBidirectional();
//设置认证信息到httpclient
httpClient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
}catch (Exception e){
logger.error("证书读取失败");
e.printStackTrace();
throw new BusinessException("证书读取失败");
}
// 根据默认超时限制初始化requestConfig
RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(25000).setConnectTimeout(25000).build();
//post通讯初始化
HttpPost httpPost = new HttpPost(url);
// 设置报文头 得指明使用UTF-8编码,否则到API服务器XML的中文不能被成功识别
httpPost.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
//添加请求报文体
StringEntity reqentity = new StringEntity(jsonParam, "UTF-8");
httpPost.setEntity(reqentity);
// 设置请求器的配置
httpPost.setConfig(requestConfig);
try {
CloseableHttpResponse response = null;
InputStream reqin = null;
try {
//打印请求报文体
reqin = httpPost.getEntity().getContent();
String reqBbody = StreamUtils.copyToString(reqin, StandardCharsets.UTF_8);
logger.info("请求数据:"+reqBbody);
//与服务端通讯
response = httpClient.execute(httpPost);
//打印通讯状态
logger.info(JSONObject.toJSONString(response.getStatusLine()));
HttpEntity entity = response.getEntity();
InputStream in = null;
try {
in = entity.getContent();
String rspBbody = StreamUtils.copyToString(in, StandardCharsets.UTF_8);
logger.info("应答为:"+rspBbody);
in.close();
result = rspBbody;
// result = EntityUtils.toString(entity, "UTF-8");
} catch (IOException e) {
logger.error("服务端应答信息读取失败");
e.printStackTrace();
throw new BusinessException("服务端应答信息读取失败");
}finally {
if (in !=null){
in.close();
}
}
} catch (IOException e) {
logger.error("与服务端通讯失败");
e.printStackTrace();
throw new BusinessException("与服务端通讯失败");
}finally {
try{
//释放资源
if (httpClient != null){
httpClient.close();
}
if (response != null){
response.close();
}
if (reqin != null){
reqin.close();
}
}catch (IOException e) {
e.printStackTrace();
}
}
} finally {
httpPost.abort();
}
return result;
}
public static SSLConnectionSocketFactory getSSLSocktetBidirectional() throws Exception {
SSLConnectionSocketFactory sslsf = null;
try{
// CA certificate is used to authenticate server
CertificateFactory cAf = CertificateFactory.getInstance("X.509");
FileInputStream caIn = new FileInputStream(CA_PATH);
X509Certificate ca = (X509Certificate) cAf.generateCertificate(caIn);
KeyStore caKs = KeyStore.getInstance("JKS");
caKs.load(null, null);
caKs.setCertificateEntry("ca-certificate", ca);
TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX");
tmf.init(caKs);
// client key and certificates are sent to server so it can authenticate us
CertificateFactory cf = CertificateFactory.getInstance("X.509");
FileInputStream crtIn = new FileInputStream(CRT_PATH);
X509Certificate caCert = (X509Certificate) cf.generateCertificate(crtIn);
crtIn.close();
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(null, null);
ks.setCertificateEntry("certificate", caCert);
ks.setKeyEntry("private-key", getPrivateKey( KEY_PATH), PASSWORD.toCharArray(), new java.security.cert.Certificate[] { caCert });
KeyManagerFactory kmf = KeyManagerFactory.getInstance("PKIX");
kmf.init(ks, PASSWORD.toCharArray());
// finally, create SSL socket factory
SSLContext context = SSLContext.getInstance("TLSv1.2");
context.init(kmf.getKeyManagers(), tmf.getTrustManagers(), new SecureRandom());
sslsf =
new SSLConnectionSocketFactory(context,null, null,
NoopHostnameVerifier.INSTANCE);
}catch (Exception e){
logger.error("证书加载失败");
e.printStackTrace();
throw new BusinessException("证书加载失败");
}
return sslsf;
}
private static PrivateKey getPrivateKey(String path) throws Exception {
//byte[] buffer = Base64.getDecoder().decode(getPem(path));
// Base64 base64 = new Base64();
BASE64Decoder decoder = new BASE64Decoder();
byte[] buffer = decoder.decodeBuffer(getPem(path));
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(buffer);
KeyFactory keyFactory = KeyFactory.getInstance("EC");
return keyFactory.generatePrivate(keySpec);
}
private static String getPem(String path) throws Exception {
FileInputStream fin = new FileInputStream(path);
BufferedReader br = new BufferedReader(new InputStreamReader(fin));
String readLine = null;
StringBuilder sb = new StringBuilder();
while ((readLine = br.readLine()) != null) {
if (readLine.charAt(0) == '-') {
continue;
} else {
sb.append(readLine);
sb.append('\r');
}
}
fin.close();
return sb.toString();
}
}
以上代码亲测有效,如果不对之处请各位大神指正,当然有更好的方法也请各位提出来