HttpClient javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated

最近在調用一些https的接口,然後採用的認證方式是用戶名+密碼。

這個時候調用接口則會提示httpclient未認證的錯誤,導致接口無法調用:

HttpClient javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated。

出現此問題主要是在請求過程中證書的問題,程序使用的客戶端並未安裝服務器要求的證書,所以會產生此問題。

下面是我找到的解決方法。

方法一: httpClient jar包版本爲4.1.x

    public static HttpClient getHttpClient(HttpClient base) {
        try {
            SSLContext ctx = SSLContext.getInstance("SSL");
            X509TrustManager tm = new X509TrustManager() {
                public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                    return null;
                }
                @Override
                public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {}
                @Override
                public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {}
            };

            ctx.init(null, new TrustManager[] { tm }, null);
            SSLSocketFactory ssf = new SSLSocketFactory(ctx, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
            ClientConnectionManager mgr = base.getConnectionManager();
            SchemeRegistry registry = mgr.getSchemeRegistry();
            registry.register(new Scheme("https", 443, ssf));
            return new DefaultHttpClient(mgr, base.getParams());
        } catch (Exception e) {
            logger.warn("{}", e);
            return null;
        }
    }

調用的方法如下:

HttpClient httpClient = ToolUtil.getHttpClient(new DefaultHttpClient());

此時問題已經完美解決了。

然而在之後的使用過程中,我發現4.1版本的httpClient jar包裏面沒有httpPatch,但最新的4.5版本是有的。於是果斷用最新的4.5.3版本的httpClient包。

用了這個jar包之後滿屏幕的刪除線,很多代碼都被@Deprecated註解掉了。改!

解決HttpClient javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated這個問題的代碼當然也是要隨着一起改的了,於是乎我找到了方法二。

方法二: httpClient jar包爲4.5.x版本。

    public static CloseableHttpClient getHttpClient() {
        try {
            SSLContext sslContext = SSLContext.getInstance("SSL");
            sslContext.init(null, new TrustManager[]{new X509TrustManager() {
                @Override
                public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {

                }

                @Override
                public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {

                }

                @Override
                public X509Certificate[] getAcceptedIssuers() {
                    return new X509Certificate[0];
                }
            }}, new SecureRandom());
            SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE);
            CloseableHttpClient closeableHttpClient = HttpClientBuilder.create().setSSLSocketFactory(socketFactory).build();
            return closeableHttpClient;
        } catch (Exception e) {
            logger.warn("create closeable http client failed!");
            return HttpClientBuilder.create().build();
        }
    }
調用示例:

httpClient = ToolUtil.getHttpClient();

在這個裏面我遇到的最大問題是SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER 竟然也被@Deprecated註釋了。然後終於找到了一個替代方案:用NoopHostnameVerifier.INSTANCE替換之。這個是在http://stackoverflow.com/questions/23201648/httpclient-4-3-x-fixing-deprecated-code-to-use-current-httpclient-implementatio 最下面一個答案中找到的。


最後附上完整的java代碼,主要是給出import頭文件。

import org.apache.http.client.HttpClient;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultHttpClient;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.UnsupportedEncodingException;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import org.apache.http.impl.client.HttpClientBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


public class ToolUtil {
    private static final Logger logger = LoggerFactory.getLogger(ToolUtil.class);

    public static HttpClient getHttpClient(HttpClient base) {
        try {
            SSLContext ctx = SSLContext.getInstance("SSL");
            X509TrustManager tm = new X509TrustManager() {
                public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                    return null;
                }
                @Override
                public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {}
                @Override
                public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {}
            };

            ctx.init(null, new TrustManager[] { tm }, null);
            SSLSocketFactory ssf = new SSLSocketFactory(ctx, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
            ClientConnectionManager mgr = base.getConnectionManager();
            SchemeRegistry registry = mgr.getSchemeRegistry();
            registry.register(new Scheme("https", 443, ssf));
            return new DefaultHttpClient(mgr, base.getParams());
        } catch (Exception e) {
            logger.warn("{}", e);
            return null;
        }
    }


    public static CloseableHttpClient getHttpClient() {
        try {
            SSLContext sslContext = SSLContext.getInstance("SSL");
            sslContext.init(null, new TrustManager[]{new X509TrustManager() {
                @Override
                public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {

                }

                @Override
                public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {

                }

                @Override
                public X509Certificate[] getAcceptedIssuers() {
                    return new X509Certificate[0];
                }
            }}, new SecureRandom());
            SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE);
            CloseableHttpClient closeableHttpClient = HttpClientBuilder.create().setSSLSocketFactory(socketFactory).build();
            return closeableHttpClient;
        } catch (Exception e) {
            logger.warn("create closeable http client failed!");
            return HttpClientBuilder.create().build();
        }
    }


}

本文參考:

http://stackoverflow.com/questions/24752485/httpclient-javax-net-ssl-sslpeerunverifiedexception-peer-not-authenticated-when

http://stackoverflow.com/questions/23201648/httpclient-4-3-x-fixing-deprecated-code-to-use-current-httpclient-implementatio


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章