使用httpclient工具绕过证书验证进行HTTPS请求

在项目中需要调用其他服务的接口,该服务需要使用https访问,对此记录了一下,使用httpclient工具绕过证书验证进行HTTPS请求。

  1. 版本1:
    import com.alibaba.fastjson.JSON;
    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.client.methods.HttpRequestBase;
    import org.apache.http.config.Registry;
    import org.apache.http.config.RegistryBuilder;
    import org.apache.http.conn.socket.ConnectionSocketFactory;
    import org.apache.http.conn.socket.PlainConnectionSocketFactory;
    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.http.impl.conn.PoolingHttpClientConnectionManager;
    import org.apache.http.util.EntityUtils;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import javax.net.ssl.SSLContext;
    import javax.net.ssl.TrustManager;
    import javax.net.ssl.X509TrustManager;
    import java.io.IOException;
    import java.io.UnsupportedEncodingException;
    import java.net.URI;
    import java.security.cert.CertificateException;
    import java.security.cert.X509Certificate;
    import java.util.Map;
    
    public class HttpClientTest {
    
        private static final Logger logger = LoggerFactory.getLogger(HttpClientTest1.class);
    
    
        /**
         * httpclient绕过证书验证进行HTTPS请求
         * url以https开头,会采用 https单向认证请求
         * yrl以http开头,会使用httpPostRequest
         *
         * @param url
         * @param params  json string
         * @param headers  http header
         * @return
         */
        public static String httpsClientSSLFuntcion(String url, Map<String, Object> headers, String params) throws Exception {
            if (url == null || !url.startsWith("http")) {
                logger.debug("httpClient发送失败,url异常!");
                return null;
            }
            //响应内容
            String responseContent = "";
            if (url.startsWith("https")) {
                CloseableHttpClient httpclient = getHttpClient_ssl();
                if (httpclient != null) {
                    CloseableHttpResponse response = null;
                    try {
                        HttpPost httpPost = new HttpPost(url);
                        //设置超时,连接超时,获取数据超时
                        RequestConfig requestConfig = RequestConfig.custom()
                                .setConnectTimeout(10000)
                                .setSocketTimeout(30000).build();
                        httpPost.setConfig(requestConfig);
                        if (headers != null) {
                            for (Map.Entry<String, Object> param : headers.entrySet()) {
                                httpPost.addHeader(param.getKey(), param.getValue().toString());
                            }
                        }
                        StringEntity se = new StringEntity(params, "UTF-8");
                        se.setContentType("application/json");
                        httpPost.setEntity(se);
                        response = httpclient.execute(httpPost); //执行POST请求
                        HttpEntity entity = response.getEntity();             //获取响应实体
                        if (null != entity) {
                            responseContent = EntityUtils.toString(entity, "UTF-8");
                            EntityUtils.consume(entity); //Consume response content
                        }
                        response.close();
                    } catch (Exception e) {
                        logger.debug("httpclient发送异常:" + e.getMessage());
                    } finally {
                        try {
                            httpclient.close();
                        } catch (Exception e) {
                            logger.debug("关闭httpclient连接异常:" + e.getMessage());
                        }//关闭连接,释放资源
                    }
                }
            } else {
                responseContent = httpPostRequest(url, headers, JSON.toJSONString(params));
            }
            return responseContent;
        }
    
    
        private static CloseableHttpClient getHttpClient_ssl() {
            X509TrustManager xtm = new X509TrustManager() {   //创建TrustManager
                public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                }
    
                public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                }
    
                public X509Certificate[] getAcceptedIssuers() {
                    return null;
                }
    
            };
            SSLContext ctx = null;
            try {
                ctx = SSLContext.getInstance("TLS");
                //使用TrustManager来初始化该上下文,TrustManager只是被SSL的Socket所使用
                ctx.init(null, new TrustManager[]{xtm}, null);
            } catch (Exception e) {
                logger.debug("httpclient异常");
            }
    
            //创建SSLSocketFactory     new String[] { "TLSv1" }, new String[]{"TLSv1.2"},
            SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(
                    ctx,
                    new String[]{"TLS"},
                    null,
                    SSLConnectionSocketFactory.getDefaultHostnameVerifier()
            );
            Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.
                    <ConnectionSocketFactory>create()
                    .register("http", PlainConnectionSocketFactory.getSocketFactory())
                    .register("https", socketFactory)
                    .build();
            // 创建ConnectionManager,添加Connection配置信息
            PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
            CloseableHttpClient closeableHttpClient = HttpClients.custom().setConnectionManager(connectionManager)
                    .build();
    
            return closeableHttpClient;
        }
    
    
        /**
         * 发送正常的post请求
         *
         * @param url
         * @param headers Map<String, Object> 请求头
         * @param params  String    参数 json字符串
         * @return String
         * @throws UnsupportedEncodingException
         */
        public static String httpPostRequest(String url, Map<String, Object> headers,
                                             String params) throws Exception {
            HttpPost httpPost = new HttpPost(url);
            try {
                RequestConfig requestConfig = RequestConfig.custom()
                        .setConnectTimeout(1000).setConnectionRequestTimeout(1000)
                        .setSocketTimeout(2000).build();
                httpPost.setConfig(requestConfig);
            } catch (Exception e) {
                return null;
            }
    
            for (Map.Entry<String, Object> param : headers.entrySet()) {
                httpPost.addHeader(param.getKey(), param.getValue().toString());
            }
            StringEntity se = new StringEntity(params);
            se.setContentType("application/json");
            httpPost.setEntity(se);
    
            return getResult(httpPost);
        }
    
        private static String getResult(HttpRequestBase request) {
            URI uri = request.getURI();
            String urlStr = uri.toString();
            if (urlStr == null || "".equals(urlStr) || !urlStr.startsWith("http")) {
                return "";
            }
            //不用连接池
            CloseableHttpClient httpClient = HttpClients.custom().build();
            try {
                CloseableHttpResponse response = httpClient.execute(request);
                try {
                    HttpEntity entity = response.getEntity();
                    if (entity != null) {
                        String result = EntityUtils.toString(entity, "UTF-8");
                        return result;
                    }
                } finally {
                    response.close();
                }
            } catch (Exception e) {
                logger.error(e.getMessage());
            } finally {
                try {
                    httpClient.close();
                } catch (IOException e) {
                    logger.error(e.getMessage());
                }
            }
    
            return "";
        }
    
    
    }
    

    在使用中调用httpsClientSSLFuntcion方法,但使用中发现报出异常:
     

    java.lang.IllegalArgumentException: TLS
    	at sun.security.ssl.ProtocolVersion.valueOf(ProtocolVersion.java:187)
    	at sun.security.ssl.ProtocolList.convert(ProtocolList.java:84)
    	at sun.security.ssl.ProtocolList.<init>(ProtocolList.java:52)
    	at sun.security.ssl.SSLSocketImpl.setEnabledProtocols(SSLSocketImpl.java:2525)
    	at org.apache.http.conn.ssl.SSLConnectionSocketFactory.createLayeredSocket(SSLConnectionSocketFactory.java:371)
    	at org.apache.http.conn.ssl.SSLConnectionSocketFactory.connectSocket(SSLConnectionSocketFactory.java:355)
    	at org.apache.http.impl.conn.DefaultHttpClientConnectionOperator.connect(DefaultHttpClientConnectionOperator.java:142)
    	at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:373)
    	at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:381)
    	at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:237)
    	at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:185)
    	at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:89)
    	at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:111)
    	at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:185)
    	at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:83)
    	at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:108)
    	at com.dzh.httpclient.HttpClientTest1.httpsClientSSLFuntcion(HttpClientTest1.java:74)
    	at com.dzh.httpclient.HttpClientTest1.main(HttpClientTest1.java:218)

    发现是TLS版本问题:对方服务器限制只能使用TLSv1.2,但是程序中制定TLS(jdk8以后默认使用TLSv1.2)
    修改后:

import com.alibaba.fastjson.JSON;
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.client.methods.HttpRequestBase;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
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.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Map;

public class HttpClientTest {

    private static final Logger logger = LoggerFactory.getLogger(HttpClientTest.class);


    /**
     * http post ,参数中有头信息  分发使用
     *
     * @param url
     * @param headers Map<String, Object> 请求头
     * @param params  String    参数 json字符串
     * @return String
     * @throws UnsupportedEncodingException
     */
    public static String httpPostRequest(String url, Map<String, Object> headers,
                                         String params) throws Exception {
        HttpPost httpPost = new HttpPost(url);
        try {
            RequestConfig requestConfig = RequestConfig.custom()
                    .setConnectTimeout(1000).setConnectionRequestTimeout(1000)
                    .setSocketTimeout(2000).build();
            httpPost.setConfig(requestConfig);
        } catch (Exception e) {
            logger.debug("httpclient发送异常:" + e.getMessage());
            return "0x001";
        }
        for (Map.Entry<String, Object> param : headers.entrySet()) {
            httpPost.addHeader(param.getKey(), param.getValue().toString());
        }
        StringEntity se = new StringEntity(params);
        se.setContentType("application/json");
        httpPost.setEntity(se);

        return getResult(httpPost);
    }


    /**
     * url以https开头,会采用 https单向认证请求
     * yrl以http开头,会使用httpPostRequest
     *
     * @param url
     * @param params Map<String, Object>
     * @return
     */
    public static String httpsClientSSLFuntcion(String url, Map<String, Object> headers, String params) throws Exception {
        if (url == null || !url.startsWith("http")) {
            logger.debug("httpClient发送失败,url异常!");
            return "{\"success\":\"false\",\"message\":\"httpClient发送失败,url异常!\"}";
        }
        String responseContent = "";                     //响应内容
        if (url.startsWith("https")) {
            CloseableHttpClient httpclient = getHttpClient_ssl();
            if (httpclient != null) {
                CloseableHttpResponse response = null;
                try {
                    HttpPost httpPost = new HttpPost(url);                        //创建HttpPost
                    //设置超时,连接超时,获取数据超时
                    RequestConfig requestConfig = RequestConfig.custom()
                            .setConnectTimeout(10000)
                            .setSocketTimeout(30000).build();
                    httpPost.setConfig(requestConfig);
                    if (headers != null) {
                        for (Map.Entry<String, Object> param : headers.entrySet()) {
                            httpPost.addHeader(param.getKey(), param.getValue().toString());
                        }
                    }
                    StringEntity se = new StringEntity(params, "UTF-8");
                    se.setContentType("application/json");
                    httpPost.setEntity(se);
                    response = httpclient.execute(httpPost); //执行POST请求
                    HttpEntity entity = response.getEntity();             //获取响应实体
                    if (null != entity) {
                        responseContent = EntityUtils.toString(entity, "UTF-8");
                        EntityUtils.consume(entity); //Consume response content
                    }
                    response.close();
                } catch (Exception e) {
                    logger.debug("httpclient发送异常:" + e.getMessage());
                } finally {
                    try {
                        httpclient.close();
                    } catch (IOException e) {
                        logger.debug("关闭httpclient连接异常:" + e.getMessage());
                    }//关闭连接,释放资源
                }
            }
        } else {
            responseContent = httpPostRequest(url, headers, JSON.toJSONString(params));
        }
        return responseContent;
    }


    /**
     * 在调用SSL之前需要重写验证方法,取消检测SSL
     * 创建ConnectionManager,添加Connection配置信息
     *
     * @return HttpClient 支持https
     */
    private static CloseableHttpClient getHttpClient_ssl() {
        X509TrustManager xtm = new X509TrustManager() {   //创建TrustManager
            public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
            }

            public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
            }

            public X509Certificate[] getAcceptedIssuers() {
                return null;
            }

        };
        //TLS1.0与SSL3.0基本上没有太大的差别,可粗略理解为TLS是SSL的继承者,但它们使用的是相同的SSLContext
        SSLContext ctx = null;
        try {
            ctx = SSLContext.getInstance("TLS");
            //使用TrustManager来初始化该上下文,TrustManager只是被SSL的Socket所使用
            ctx.init(null, new TrustManager[]{xtm}, null);
        } catch (Exception e) {
            e.printStackTrace();
        }
        SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(ctx, NoopHostnameVerifier.INSTANCE);
        Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.
                <ConnectionSocketFactory>create()
                .register("http", PlainConnectionSocketFactory.getSocketFactory())
                .register("https", socketFactory)
                .build();
        // 创建ConnectionManager,添加Connection配置信息
        PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
        CloseableHttpClient closeableHttpClient = HttpClients.custom().setConnectionManager(connectionManager)
                .build();


        return closeableHttpClient;
    }


    private static String getResult(HttpRequestBase request) {
        URI uri = request.getURI();
        String urlStr = uri.toString();
        if (urlStr == null || "".equals(urlStr) || !urlStr.startsWith("http")) {
            return "0x001";
        }
        //不用连接池
        CloseableHttpClient httpClient = HttpClients.custom().build();
        try {
            CloseableHttpResponse response = httpClient.execute(request);
            try {
                HttpEntity entity = response.getEntity();
                if (entity != null) {
                    String result = EntityUtils.toString(entity, "UTF-8");
                    return result;
                }
            } finally {
                response.close();
            }
        } catch (Exception e) {
            logger.error(e.getMessage());
        } finally {
            try {
                httpClient.close();
            } catch (IOException e) {
                logger.error(e.getMessage());
            }
        }

        return "0x001";
    }


}

 

posted @ 2019-12-17 17:16  DingDingDongDong  阅读(492)  评论(0编辑  收藏  举报