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

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

  • 一·HttpsUtil工具类
  • 二·SSLUtil工具类

一·HttpsUtil工具类

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工具类

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
 * 

* @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 { } } }

你可能感兴趣的:(总结,java,ssl,https,自签证书验证,ssl验证,https忽略证书验证,https工具类)