httpclient4.x访问https[通俗易懂]

httpclient4.x访问https[通俗易懂]https有单向认证和双向认证之分,单向认证即客户端只会认证服务端,双向认证是客户端需要认证服务端,服务端也需要认证客户端。先说单向认证,浏览器访问服务端,服务端接收请求,会把证书(包含密钥和其他信息)和加密后响应返回给浏览器。如果这个证书不是向第三方权威机构申请的,浏览器会提示证书有问题(使用httpclient访问的话会报错)。如果忽略错误,则浏览器接受证书并解密响应,发送的数据也用此密钥

大家好,又见面了,我是你们的朋友全栈君。

https有单向认证和双向认证之分,单向认证即客户端只会认证服务端,双向认证是客户端需要认证服务端,服务端也需要认证客户端。

先说单向认证,浏览器访问服务端,服务端接收请求,会把证书(包含密钥和其他信息)和加密后响应返回给浏览器。如果这个证书不是向第三方权威机构申请的,浏览器会提示证书有问题(使用httpclient访问的话会报错)。如果忽略错误,则浏览器接受证书并解密响应,发送的数据也用此密钥加密。

双向认证的话,客户端访问服务端也要提供证书,否则服务端拒绝响应。而且如果是自己生产的证书,需要把客户端的证书导入到服务端的信任列表中,否则服务端也会拒绝。

前面说到,如果服务端的证书不是向第三方权威机构申请,使用httpclient访问会报错。解决办法由两种,第一种是将证书导入jre的密钥库的信任列表;第二种是让他不去验证服务端证书。如果需要双向认证,还需要为httpclient指定客户端需要使用的证书。


package cloudolp;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
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.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.ssl.TrustStrategy;

import javax.net.ssl.SSLContext;
import java.io.File;
import java.io.FileInputStream;
import java.security.KeyStore;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

/**
 * 
 */
public class HttpClientFactory {
    private static CloseableHttpClient httpClient;

    public synchronized static CloseableHttpClient getCloseableHttpClient(){
        if(httpClient==null){
            SSLConnectionSocketFactory sslConnectionSocketFactory=null;
            try{
                FileInputStream keyin = new FileInputStream(new File("d:\\client.p12"));
                KeyStore keystore = KeyStore.getInstance("PKCS12");
                keystore.load(keyin, "client1".toCharArray());
                keyin.close();
                final TrustStrategy trustStrategy=new TrustStrategy() {
                    @Override
                    public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                        return true;
                    }
                };
                SSLContext sslcontext = SSLContexts.custom()
                        .loadTrustMaterial(trustStrategy)
                        .loadKeyMaterial(keystore, "client1".toCharArray())
                        .build();
                sslConnectionSocketFactory = new SSLConnectionSocketFactory(
                        sslcontext,
                        SSLConnectionSocketFactory.getDefaultHostnameVerifier());

            } catch(Exception e){
                LogFactory.getLog(HttpClientFactory.class).error(e);
            }
            Registry<ConnectionSocketFactory> registry= RegistryBuilder.<ConnectionSocketFactory>create()
                    .register("http", PlainConnectionSocketFactory.getSocketFactory())
                    .register("https", sslConnectionSocketFactory)
                    .build();
            PoolingHttpClientConnectionManager connectionManager=new PoolingHttpClientConnectionManager(registry);
            connectionManager.setMaxTotal(200);
            connectionManager.setDefaultMaxPerRoute(20);
            HttpClientBuilder httpClientBuilder=HttpClients.custom();
//            if(sslConnectionSocketFactory!=null){
//                httpClientBuilder.setSSLSocketFactory(sslConnectionSocketFactory);
//            }
            httpClientBuilder.setConnectionManager(connectionManager);
            httpClient = httpClientBuilder.build();
        }
        return httpClient;
    }
}


final TrustStrategy trustStrategy=new TrustStrategy() {
                    @Override
                    public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                        return true;
                    }
                };

自己实现证书信任策略,这里我们之间返回true,这样所有的服务端证书都会被信任,这样如果服务端的证书不是权威机构颁布的,httclient就不会报错了

SSLContext sslcontext = SSLContexts.custom()
                        .loadTrustMaterial(trustStrategy)
                        .loadKeyMaterial(keystore, "client1".toCharArray())
                        .build();

loadTrustMaterial()是设置服务端证书的信任策略,这个方法有很多重载的方法,比如可以使用密钥库

loadKeyMaterial()设置客户端需要发送到服务端的证书,有两个参数,密钥库和密钥密码,密钥库是client1.p12,keystore.load()也有两个参数,一个是真
正的存储地址,一个是密钥库的秘密(有可能和密钥的秘密不一样)。这里的证书类型是PKCS12,是个人证书。

FileInputStream keyin = new FileInputStream(new File("d:\\client.p12"));
                KeyStore keystore = KeyStore.getInstance("PKCS12");
                keystore.load(keyin, "client1".toCharArray());

最后通过SSLContext 创建套接字连接工厂,并注册到连接管理器。

注意我是用的CloseableHttpClient和PoolingHttpClientConnectionManager

如果用的是DefaultHttpClient,可以用下面这段代码

HttpClient httpClient = new DefaultHttpClient(); 
SSLSocketFactory socketFactory = new SSLSocketFactory(sslContext); 
Scheme sch = new Scheme(“https”, 8443, socketFactory); 
httpClient.getConnectionManager().getSchemeRegistry().register(sch);

但如果用的不是DefaultHttpClient,而是CloseableHttpClient,代码ttpClient.getConnectionManager().getSchemeRegistry().register(sch)会报错,在实际中应该很少会使用DefaultHttpClient。

如果没有设置连接管理器,则可在builder中设置套接字连接工厂

httpClientBuilder.setSSLSocketFactory(sslConnectionSocketFactory);

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/163258.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号