总结:使用JDK原生HttpsURLConnection,封装HttpsUtil工具类,加载自定义证书验证,忽略ssl证书验证
一·HttpsUtil工具类
java
package com.example.util;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.security.KeyStore;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
/**
* https请求工具类
*/
public class HttpsUtil {
private static int timeOut = 60000; // https超时时间
public static void main(String[] args) throws IOException {
//测试默认的受信任根证书,https请求
// String s = doGet("https://blog.csdn.net/weixin_48033662?spm=1010.2135.3001.5343");
// System.out.println(s);
//测试自定义受信任证书的https请求
String s2 = doGet("https://localhost:8443/hello",
"/Users/ideal/私人文件夹/JavaProjects/springboot3-multi-module-demo/SpringBoot-https-demo/src/main/resources/public_cert.pem");
System.out.println(s2);
}
/**
* get请求,不能访问加密URL
* 使用自定义受信任的根证书
*
* @param urlAddress https地址
* @param certPath 本地证书路径
* @return
* @author LiuMingFu
* @date 2025/2/14
*/
public static String doGet(String urlAddress, String certPath) {
try {
/**
* 1. 封装自定义的受信任CA证书
*
* 作用:创建一个CertificateFactory对象,用于处理X.509格式的证书(自签证书模式)。
* 说明:X.509是一种标准的证书格式,常用于SSL/TLS通信。
*/
CertificateFactory cf = CertificateFactory.getInstance("X.509");
//从指定路径加载PEM格式的证书文件,并将其转换为X509Certificate对象
X509Certificate caCert = (X509Certificate) cf.generateCertificate(
//读取自签证书文件
new FileInputStream(certPath)
);
/**
* 2. 创建KeyStore并加载CA证书
*
* 作用:创建一个KeyStore对象,用于存储证书和密钥。
* 说明:KeyStore.getDefaultType()返回默认的密钥库类型(通常是JKS或PKCS12)。
*/
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
/**
* 作用:初始化KeyStore对象。
*
* 第一个参数为null,表示不加载现有的密钥库文件。
* 第二个参数为null,表示使用默认密码。
*/
keyStore.load(null, null);
//将证书添加到KeyStore中。"caCert":证书的别名,用于标识证书
keyStore.setCertificateEntry("caCert", caCert);
/**
* 3. 创建一个TrustManagerFactory对象,用于管理信任的证书
* TrustManagerFactory.getDefaultAlgorithm()返回默认的算法(通常是PKIX)
*/
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
/**
* 作用:使用KeyStore初始化TrustManagerFactory。
* 说明:keyStore中存储的证书将被用于验证服务器的证书。
*/
tmf.init(keyStore);
//4.创建一个SSLContext对象,用于管理SSL/TLS协议的配置。TLS是SSL的升级版,目前广泛使用
SSLContext sc = SSLContext.getInstance("TLS");
/**
* 初始化SSLContext
* 第一个参数为null,表示不使用客户端证书。
* 第二个参数为tmf.getTrustManagers(),表示使用TrustManagerFactory生成的信任管理器。
* 第三个参数为null,表示使用默认的随机数生成器。
*/
sc.init(null, tmf.getTrustManagers(), null);
//5. 设置默认的SSLSocketFactory,所有后续的HttpsURLConnection请求都会使用这个SSLSocketFactory来建立SSL/TLS连接。
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
// 6. 发起HTTPS请求
URL url = new URL(urlAddress);
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
connection.setRequestMethod("GET");
int responseCode = connection.getResponseCode();
System.out.println("Response Code: " + responseCode);
/**
* 创建一个BufferedReader对象,用于读取服务器的响应内容。
* connection.getInputStream():获取服务器的输入流。
* InputStreamReader:将字节流转换为字符流。
* BufferedReader:提供缓冲功能,提高读取效率
*/
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String inputLine;
StringBuilder response = new StringBuilder();
//逐行读取响应内容并拼接到response中,in.readLine()读取一行内容,直到返回null(表示读取完毕)
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
//关闭流
in.close();
System.out.println("Response Content: " + response.toString());
return response.toString();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* get请求,不能访问加密URL
* 使用默认的受信任根证书
*
* @param requestURL 请求地址
* @return 响应结果
* @throws IOException
*/
public static String doGet(String requestURL) throws IOException {
BufferedReader inReader = null;
InputStream in = null;
String responseBody = "";
try {
//创建url地址
URL url = new URL(requestURL);
//使用https类型的url连接对象
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
//设置连接超时
conn.setConnectTimeout(timeOut);
//设置读取超时
conn.setReadTimeout(timeOut);
//设置请求方法,必须大写
conn.setRequestMethod("GET");
//设置请求头信息
conn.setRequestProperty("Content-Type", "application/json");
/*
* connect()会根据HttpURLConnection对象的配置值生成HTTP头部信息,且建立tcp连接,但是没有发送http请求
* 所有的配置信息,都必须在connect()方法之前添加,后面的添加不进去。
*/
conn.connect();
/*
* 开始发起get类型http请求,获取响应数据
*/
//实际发送url的http请求
if (HttpsURLConnection.HTTP_OK == conn.getResponseCode()) {
//获取正常响应流
in = conn.getInputStream();
} else {
//获取异常响应流
in = conn.getErrorStream();
}
//读取响应内容
inReader = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8));
StringBuilder sb = new StringBuilder();
int len;
char[] tmp = new char[256];
while ((len = inReader.read(tmp)) > 0) {
sb.append(tmp, 0, len);
}
responseBody = sb.toString();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (inReader != null) {
inReader.close();
}
if (in != null) {
in.close();
}
}
return responseBody;
}
/**
* post请求,不能访问加密URL
* 使用默认的受信任根证书
*
* @param requestURL 请求地址
* @param body 请求体
* @return 响应结果
* @throws IOException
*/
public static String doPost(String requestURL, String body) throws IOException {
BufferedReader inReader = null;
InputStream in = null;
String responseBody = "";
OutputStream outputStream = null;
BufferedWriter writer = null;
try {
//创建链接地址
URL url = new URL(requestURL);
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
//设置是否允许从httpUrlConnection读取数据,默认是true
conn.setDoInput(true);
//设置是否向httpUrlConnection输出参数,因为这个是post请求,所以必须开启
conn.setDoOutput(true);
//设置连接超时
conn.setConnectTimeout(timeOut);
//设置读取超时
conn.setReadTimeout(timeOut);
//设置请求方法,必须大写
conn.setRequestMethod("POST");
//设置请求头信息
conn.setRequestProperty("Content-Type", "application/json");
/*
* connect()会根据HttpURLConnection对象的配置值生成HTTP头部信息,且建立tcp连接,但是没有发送http请求
* 所有的请求头配置信息,都必须在connect()方法之前添加,后面的添加不进去。
*/
conn.connect();
/*
* 往post连接里面写入必要的请求体-参数
*/
//获取conn的输出流
outputStream = conn.getOutputStream();
//将字节流转换为字符流
writer = new BufferedWriter(new OutputStreamWriter(outputStream, StandardCharsets.UTF_8));
//往连接中写入参数,body可以是name=lmf&age=23键值对拼接形式,也可以是json字符串形式
writer.write(body);
//必须刷新流空间的数据
writer.flush();
/*
* 开始发起post类型http请求,获取响应数据
*/
//实际发送url的http请求
if (HttpsURLConnection.HTTP_OK == conn.getResponseCode()) {
//获取正常响应流
in = conn.getInputStream();
} else {
//获取异常响应流
in = conn.getErrorStream();
}
//读取响应内容
inReader = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8));
StringBuilder sb = new StringBuilder();
int len;
char[] tmp = new char[256];
while ((len = inReader.read(tmp)) > 0) {
sb.append(tmp, 0, len);
}
//最终响应内容字符串
responseBody = sb.toString();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (writer != null) {
writer.close();
}
if (outputStream != null) {
outputStream.close();
}
if (inReader != null) {
inReader.close();
}
if (in != null) {
in.close();
}
}
return responseBody;
}
}
二·SSLUtil工具类
java
package com.example.util;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
/**
* @Description TODO
* <p>
* @Author LiuMingFu
* @Date 2024/1/8 13:59
*/
public class SSLUtil {
public static void main(String[] args) throws NoSuchAlgorithmException, KeyManagementException, IOException {
//忽略单个https连接的证书校验
URL url = new URL("https://localhost:8443/hello");
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
conn.setRequestMethod("GET");
// 仅忽略当前连接的SSL验证
SSLUtil.trustSSLCertificatesByOneConnect(conn);
// 读取响应码
int code = conn.getResponseCode();
System.out.println("Response Code: " + code);
// 读取响应内容
BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
StringBuilder response = new StringBuilder();
String inputLine;
while ((inputLine = reader.readLine()) != null) {
response.append(inputLine);
}
reader.close();
System.out.println("Response Content: " + response.toString());
System.out.println("========================================================================================");
// 全局忽略HTTPS证书校验,下面所有的https请求都会忽略证书校验
SSLUtil.trustAllSSLCertificates();
String s = HttpsUtil.doGet("https://localhost:8443/hello");
System.out.println(s);
}
/**
* 演示:忽略HTTPS证书校验流程
*
* @param args
*/
public static void main2(String[] args) {
try {
// 1. 创建 TrustAllManager
TrustManager[] trustAllCerts = new TrustManager[]{
new TrustAllManager()
};
// 2. 初始化 SSLContext
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
// 3. 设置默认的 SSLSocketFactory
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
// 4. 设置默认的 HostnameVerifier,接受所有主机名
HttpsURLConnection.setDefaultHostnameVerifier((hostname, session) -> true);
// 5. 发起 HTTPS 请求
URL url = new URL("https://localhost:8443/hello");
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
connection.setRequestMethod("GET");
int responseCode = connection.getResponseCode();
System.out.println("Response Code: " + responseCode);
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String inputLine;
StringBuilder response = new StringBuilder();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
System.out.println("Response Content: " + response.toString());
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 针对全局所有https连接,忽略ssl校验
*
* @return
* @author LiuMingFu
* @date 2024/1/8
*/
public static void trustAllSSLCertificates() throws NoSuchAlgorithmException, KeyManagementException {
//创建证书数组
TrustManager[] trustAllCerts = new TrustManager[1];
//设置一个忽略ssl校验的证书管理器
trustAllCerts[0] = new TrustAllManager();
//获取一个ssl实例,并初始化设置证书数组等等
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, null);
//设置ssl连接socket流处理工厂类
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
//ssl协议域名校验,默认直接true,相当于忽略ssl校验
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String urlHostName, SSLSession session) {
return true;
}
});
}
/**
* 针对单个连接,忽略https的ssl校验
*
* @param connection https连接对象
* @return
* @author LiuMingFu
* @date 2024/1/8
*/
public static void trustSSLCertificatesByOneConnect(URLConnection connection) throws NoSuchAlgorithmException, KeyManagementException {
HttpsURLConnection httpsURLConnection = (HttpsURLConnection) connection;
//创建证书数组
TrustManager[] trustAllCerts = new TrustManager[1];
//设置一个忽略ssl校验的证书管理器
trustAllCerts[0] = new TrustAllManager();
//获取一个ssl实例,并初始化设置证书数组等等
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, null);
//设置ssl连接socket流处理工厂类
httpsURLConnection.setSSLSocketFactory(sc.getSocketFactory());
//ssl协议域名校验,默认直接true,相当于忽略ssl校验
httpsURLConnection.setHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String urlHostName, SSLSession session) {
return true;
}
});
}
/**
* 证书管理实现类,该类会对客户端、服务端进行各种校验,这里直接默认全部通过
*
* @author LiuMngFu
* @return a
* @date 2024/1/8
*/
private static class TrustAllManager implements X509TrustManager {
/**
* 返回受信任的CA证书数组
* 这里返回 null,表示不限制任何CA证书(即接受所有证书)
*
* @return
* @author LiuMingFu
* @date 2025/2/14
*/
@Override
public X509Certificate[] getAcceptedIssuers() {
return null;
}
/**
* 验证服务器证书是否受信任
* 这里方法体为空,表示不进行任何验证(即信任所有服务器证书),这种做法会绕过服务器的证书验证,通常用于测试环境或信任特定服务器时。
*
* @param certs:服务器提供的证书链。
* @param authType:认证类型(如 RSA、DSA 等)
* @return
* @author LiuMingFu
* @date 2025/2/14
*/
@Override
public void checkServerTrusted(X509Certificate[] certs, String authType) throws CertificateException {
}
/**
* 验证客户端证书是否受信任
* 这里方法体为空,表示不进行任何验证(即信任所有客户端证书),这种方法通常用于双向认证(mTLS)场景,但在这里没有实际验证逻辑
*
* @param certs:客户端提供的证书链。
* @param authType:认证类型(如 RSA、DSA 等)
* @return
* @author LiuMingFu
* @date 2025/2/14
*/
@Override
public void checkClientTrusted(X509Certificate[] certs, String authType) throws CertificateException {
}
}
}