HttpClient4实现SSL双向认证的客户端(二)

在上篇文章中写到了如何实现服务端程序,主要是netty实现的。还有如何生成证书和密钥库。

这篇文章主要讲客户端如何实现:

 

httpclient实现连接池并进行ssl通信

HttpClientUtils2.java

package https;

import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.methods.RequestBuilder;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.routing.HttpRoute;
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.SSLContexts;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
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.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import javax.net.ssl.SSLContext;
import java.io.File;
import java.io.FileInputStream;
import java.security.KeyStore;
import java.security.SecureRandom;
import java.util.*;

/**
 * ssl通信的client
 */
public class HttpClientUtils2 {

    private static PoolingHttpClientConnectionManager secureConnectionManager;
    private static HttpClientBuilder secureHttpBulder = null;
    private static RequestConfig requestConfig = null;
    private static int MAXCONNECTION = 10;
    private static int DEFAULTMAXCONNECTION = 5;

    private static String CLIENT_KEY_STORE = "E:\\https\\client.keystore";
    private static String CLIENT_TRUST_KEY_STORE = "E:\\https\\client.truststore";
    private static String CLIENT_KEY_STORE_PASSWORD = "123456";
    private static String CLIENT_TRUST_KEY_STORE_PASSWORD = "123456";
    private static String CLIENT_KEY_PASS = "123456";

    /**
     * 进行安全通信的主机和端口
     */
    private static String HOST = "127.0.0.1";
    private static int PORT = 8888;

    static {
        //设置http的状态参数
        requestConfig = RequestConfig.custom()
                .setSocketTimeout(5000)
                .setConnectTimeout(5000)
                .setConnectionRequestTimeout(5000)
                .build();

        try {
            KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
            FileInputStream trustStoreInput = new FileInputStream(new File(CLIENT_TRUST_KEY_STORE));
            trustStore.load(trustStoreInput, CLIENT_TRUST_KEY_STORE_PASSWORD.toCharArray());
            KeyStore clientKeyStore = KeyStore.getInstance(KeyStore.getDefaultType());
            FileInputStream clientKeyStoreInput = new FileInputStream(new File(CLIENT_KEY_STORE));
            clientKeyStore.load(clientKeyStoreInput, CLIENT_KEY_STORE_PASSWORD.toCharArray());

            SSLContext sslContext = SSLContexts.custom()
                    .loadTrustMaterial(trustStore, new TrustSelfSignedStrategy())
                    .loadKeyMaterial(clientKeyStore, CLIENT_KEY_PASS.toCharArray())
                    .setSecureRandom(new SecureRandom())
                    .useSSL()
                    .build();


            ConnectionSocketFactory plainSocketFactory = new PlainConnectionSocketFactory();
            SSLConnectionSocketFactory sslSocketFactoy = new SSLConnectionSocketFactory(
                    sslContext, new String[]{"SSLv3"}, null,
                    SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);

            Registry<ConnectionSocketFactory> r = RegistryBuilder.<ConnectionSocketFactory>create()
                    .register("http", plainSocketFactory)
                    .register("https", sslSocketFactoy)
                    .build();

            secureConnectionManager = new PoolingHttpClientConnectionManager(r);
            HttpHost target = new HttpHost(HOST, PORT, "https");
            secureConnectionManager.setMaxTotal(MAXCONNECTION);
            //设置每个Route的连接最大数
            secureConnectionManager.setDefaultMaxPerRoute(DEFAULTMAXCONNECTION);
            //设置指定域的连接最大数
            secureConnectionManager.setMaxPerRoute(new HttpRoute(target), 20);
            secureHttpBulder = HttpClients.custom().setConnectionManager(secureConnectionManager);
        } catch (Exception e) {
            throw new Error("Failed to initialize the server-side SSLContext", e);
        }
    }

    public static CloseableHttpClient getSecureConnection() throws Exception {
        return secureHttpBulder.build();
    }


    public static HttpUriRequest getRequestMethod(Map<String, String> map, String url, String method) {
        List<NameValuePair> params = new ArrayList<NameValuePair>();
        Set<Map.Entry<String, String>> entrySet = map.entrySet();
        for (Map.Entry<String, String> e : entrySet) {
            String name = e.getKey();
            String value = e.getValue();
            NameValuePair pair = new BasicNameValuePair(name, value);
            params.add(pair);
        }
        HttpUriRequest reqMethod = null;
        if ("post".equals(method)) {
            reqMethod = RequestBuilder.post().setUri(url)
                    .addParameters(params.toArray(new BasicNameValuePair[params.size()]))
                    .setConfig(requestConfig).build();
        } else if ("get".equals(method)) {
            reqMethod = RequestBuilder.get().setUri(url)
                    .addParameters(params.toArray(new BasicNameValuePair[params.size()]))
                    .setConfig(requestConfig).build();
        }
        return reqMethod;
    }


    public static void main(String args[]) throws Exception {
        Map<String, String> map = new HashMap<String, String>();
        map.put("account", "sdsdsd");
        map.put("password", "98765");

        HttpClient client = getSecureConnection(); //使用ssl通信
        HttpUriRequest post = getRequestMethod(map, "https://127.0.0.1:8888/", "post");
        HttpResponse response = client.execute(post);

        if (response.getStatusLine().getStatusCode() == 200) {
            HttpEntity entity = response.getEntity();
            String message = EntityUtils.toString(entity, "utf-8");
            System.out.println(message);
        } else {
            System.out.println("请求失败");
        }
    }
}

上面的httpclient实现了连接池,并可以进行ssl双向认证的通信过程。其实也可以进行不加密的http通信。

运行结果:

服务器端

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

Your session is protected by TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA cipher suite.

 

VERSION: HTTP/1.1

 

REQUEST_URI: /

 

HEADER: Content-Type=application/x-www-form-urlencoded; charset=ISO-8859-1

 

HEADER: Host=127.0.0.1:8888

 

HEADER: Connection=Keep-Alive

 

HEADER: User-Agent=Apache-HttpClient/4.3.3 (java 1.5)

 

HEADER: Accept-Encoding=gzip,deflate

 

HEADER: Content-Length=29

 

七月 10, 2014 11:55:07 上午 https.HttpDemoServerHandler exceptionCaught

警告: 

java.io.IOException: 远程主机强迫关闭了一个现有的连接。

有异常,这不是主要的,是因为没有关闭连接。

客户端

WELCOME TO THE WILD WILD WEB SERVER

===================================

VERSION: HTTP/1.1

REQUEST_URI: /

 

HEADER: Content-Type=application/x-www-form-urlencoded; charset=ISO-8859-1

HEADER: Host=127.0.0.1:8888

HEADER: Connection=Keep-Alive

HEADER: User-Agent=Apache-HttpClient/4.3.3 (java 1.5)

HEADER: Accept-Encoding=gzip,deflate

HEADER: Content-Length=29

 

Is Chunked: false

IsMultipart: false

 

BODY Attribute: Attribute:Mixed: password=98765

 

BODY Attribute: Attribute:Mixed: account=sdsdsd

 

END OF POST CONTENT

 

Process finished with exit code 0

 

httpclien客户端二

httpclient还有一种方式可以进行ssl通信。下面看这段代码:

ClientCustomSSL.java

package https;

import java.io.File;
import java.io.FileInputStream;
import java.security.KeyStore;

import javax.net.ssl.SSLContext;

import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

/**
 * This example demonstrates how to create secure connections with a custom SSL
 * context.
 */
public class ClientCustomSSL {

    private static String CLIENT_KEY_STORE = "E:\\https\\client.keystore";
    private static String CLIENT_TRUST_KEY_STORE = "E:\\https\\client.truststore";
    private static String CLIENT_KEY_STORE_PASSWORD = "123456";
    private static String CLIENT_TRUST_KEY_STORE_PASSWORD = "123456";
    private static String CLIENT_KEY_PASS = "123456";


    public final static void main(String[] args) throws Exception {


        KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
        FileInputStream instream = new FileInputStream(new File(CLIENT_TRUST_KEY_STORE));
        try {
            trustStore.load(instream, CLIENT_TRUST_KEY_STORE_PASSWORD.toCharArray());
        } finally {
            instream.close();
        }

        KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
        FileInputStream keyStoreInput = new FileInputStream(new File(CLIENT_KEY_STORE));
        try {
            keyStore.load(keyStoreInput, CLIENT_KEY_STORE_PASSWORD.toCharArray());
        } finally {
            keyStoreInput.close();
        }

        // Trust own CA and all self-signed certs
        SSLContext sslcontext = SSLContexts.custom()
                .loadTrustMaterial(trustStore, new TrustSelfSignedStrategy())
                .loadKeyMaterial(keyStore, CLIENT_KEY_PASS.toCharArray())
                .build();
        // Allow TLSv1 protocol only
        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
                sslcontext,
                new String[]{"SSLv3"},
                null,
                SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
        CloseableHttpClient httpclient = HttpClients.custom()
                .setSSLSocketFactory(sslsf)
                .build();
        try {

            HttpPost httpPost = new HttpPost("https://127.0.0.1:8888/");

            System.out.println("executing request" + httpPost.getRequestLine());

            CloseableHttpResponse response = httpclient.execute(httpPost);
            try {
                HttpEntity entity = response.getEntity();

                System.out.println("----------------------------------------");
                System.out.println(response.getStatusLine());
                if (entity != null) {
                    System.out.println("Response content length: " + entity.getContentLength());
                }
                EntityUtils.consume(entity);
            } finally {
                response.close();
            }
        } finally {
            httpclient.close();
        }
    }
}

上面这段代码没有用到连接池,比较简单的实现了双向认证的ssl通信过程。

运行结果:

----------------------------------------

HTTP/1.1 200 OK

Response content length: -1

 

Process finished with exit code 0

==========END==========

转载于:https://my.oschina.net/xinxingegeya/blog/289264

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值