总结:使用JDK原生HttpsURLConnection,封装HttpsUtil工具类,加载自定义证书验证,忽略ssl证书验证

总结:使用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 {
        }
    }
}
相关推荐
小梁不秃捏3 小时前
深入浅出Java虚拟机(JVM)核心原理
java·开发语言·jvm
yngsqq6 小时前
c# —— StringBuilder 类
java·开发语言
星星点点洲6 小时前
【操作幂等和数据一致性】保障业务在MySQL和COS对象存储的一致
java·mysql
遥遥远方 近在咫尺6 小时前
HTTPS原理
网络协议·https
xiaolingting6 小时前
JVM层面的JAVA类和实例(Klass-OOP)
java·jvm·oop·klass·instanceklass·class对象
编程星空7 小时前
HTTP 和 HTTPS 的区别
网络协议·http·https
风口上的猪20157 小时前
thingboard告警信息格式美化
java·服务器·前端
追光少年33227 小时前
迭代器模式
java·迭代器模式
超爱吃士力架8 小时前
MySQL 中的回表是什么?
java·后端·面试
扣丁梦想家8 小时前
设计模式教程:装饰器模式(Decorator Pattern)
java·前端·装饰器模式