• 如何使用Java访问双向认证的Https资源


    本文的相关源码位于 https://github.com/dreamingodd/CA-generation-demo 

    0.Nginx配置Https双向认证

    首先配置Https双向认证的服务器资源。

    可以参考:http://www.cnblogs.com/dreamingodd/p/7357029.html

    完成之后如下效果:

    1.导入cacerts进行访问

    首先将服务器证书导入keystore cacerts,默认密码为changeit,如果需要修改密码就改一下。

    keytool -import -alias ssl.demo.com -keystore cacerts -file C:Developmentdeploymentsslca-demoserver.crt

    需要使用管理员权限到你使用的JDK security目录下执行(注意如果你有多个JDK的情况),效果如下:

    然后使用Java访问:

     1 package me.dreamingodd.ca;
     2 
     3 import org.apache.http.HttpEntity;
     4 import org.apache.http.client.methods.CloseableHttpResponse;
     5 import org.apache.http.client.methods.HttpGet;
     6 import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
     7 import org.apache.http.impl.client.CloseableHttpClient;
     8 import org.apache.http.impl.client.HttpClients;
     9 import org.apache.http.ssl.SSLContexts;
    10 import org.apache.http.util.EntityUtils;
    11 
    12 import javax.net.ssl.SSLContext;
    13 import java.io.File;
    14 import java.io.FileInputStream;
    15 import java.io.InputStream;
    16 import java.security.KeyStore;
    17 
    18 
    19 /**
    20  * #1
    21  * HTTPS 双向认证 - direct into cacerts
    22  * @Author Ye_Wenda
    23  * @Date 7/11/2017
    24  */
    25 public class HttpsKeyStoreDemo {
    26     // 客户端证书路径,用了本地绝对路径,需要修改
    27     private final static String PFX_PATH = "C:\Development\deployment\ssl\ca-demo\client.p12";
    28     private final static String PFX_PWD = "demo"; //客户端证书密码及密钥库密码
    29 
    30     public static String sslRequestGet(String url) throws Exception {
    31         KeyStore keyStore = KeyStore.getInstance("PKCS12");
    32         InputStream instream = new FileInputStream(new File(PFX_PATH));
    33         try {
    34             // 这里就指的是KeyStore库的密码
    35             keyStore.load(instream, PFX_PWD.toCharArray());
    36         } finally {
    37             instream.close();
    38         }
    39 
    40         SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, PFX_PWD.toCharArray()).build();
    41         SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext
    42                 , new String[] { "TLSv1" }  // supportedProtocols ,这里可以按需要设置
    43                 , null  // supportedCipherSuites
    44                 , SSLConnectionSocketFactory.getDefaultHostnameVerifier());
    45 
    46         CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
    47         try {
    48             HttpGet httpget = new HttpGet(url);
    49 //          httpost.addHeader("Connection", "keep-alive");// 设置一些heander等
    50             CloseableHttpResponse response = httpclient.execute(httpget);
    51             try {
    52                 HttpEntity entity = response.getEntity();
    53                 // 返回结果
    54                 String jsonStr = EntityUtils.toString(response.getEntity(), "UTF-8");
    55                 EntityUtils.consume(entity);
    56                 return jsonStr;
    57             } finally {
    58                 response.close();
    59             }
    60         } finally {
    61             httpclient.close();
    62         }
    63     }
    64 
    65     public static void main(String[] args) throws Exception {
    66         System.out.println(sslRequestGet("https://ssl.demo.com/"));
    67     }
    68 
    69 }

    运行结果如下:

     

    2.生成truststore库文件进行访问-原生方式

    如果服务器的JDK/JRE不能随便改动,我们还可以使用生成truststore库的方式来实现。

    首先通过ca.crt生成自己的truststore,把ca.crt复制一份,重命名为ca.cer,复制到security目录下,执行

    keytool -keystore demo.truststore -keypass demodemo -storepass demodemo -alias DemoCA -import -trustcacerts -file ca.cer

    效果如下:

    使用生成的demo.truststore和client.p12进行java访问:

     1 package me.dreamingodd.ca;
     2 
     3 import javax.net.ssl.*;
     4 import java.io.*;
     5 import java.net.URL;
     6 import java.nio.charset.Charset;
     7 import java.security.KeyStore;
     8 
     9 
    10 /**
    11  * #2
    12  * HTTPS 双向认证 - use truststore
    13  * 原生方式
    14  * @Author Ye_Wenda
    15  * @Date 7/11/2017
    16  */
    17 public class HttpsTruststoreNativeDemo {
    18     // 客户端证书路径,用了本地绝对路径,需要修改
    19     private final static String CLIENT_CERT_FILE = "C:/Development/deployment/ssl/ca-demo/client.p12";
    20     // 客户端证书密码
    21     private final static String CLIENT_PWD = "demo";
    22     // 信任库路径
    23     private final static String TRUST_STRORE_FILE = "C:\Development\deployment\ssl\ca-demo\demo.truststore";
    24     // 信任库密码
    25     private final static String TRUST_STORE_PWD = "demodemo";
    26 
    27 
    28     private static String readResponseBody(InputStream inputStream) throws IOException {
    29         try {
    30             BufferedReader br = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("UTF-8")));
    31             StringBuffer sb = new StringBuffer();
    32             String buff = null;
    33             while((buff = br.readLine()) != null){
    34                 sb.append(buff+"
    ");
    35             }
    36             return sb.toString();
    37         } finally {
    38             inputStream.close();
    39         }
    40     }
    41 
    42     public static void httpsCall() throws Exception {
    43         // 初始化密钥库
    44         KeyManagerFactory keyManagerFactory = KeyManagerFactory
    45                 .getInstance("SunX509");
    46         KeyStore keyStore = getKeyStore(CLIENT_CERT_FILE, CLIENT_PWD, "PKCS12");
    47         keyManagerFactory.init(keyStore, CLIENT_PWD.toCharArray());
    48 
    49         // 初始化信任库
    50         TrustManagerFactory trustManagerFactory = TrustManagerFactory
    51                 .getInstance("SunX509");
    52         KeyStore trustkeyStore = getKeyStore(TRUST_STRORE_FILE, TRUST_STORE_PWD,"JKS");
    53         trustManagerFactory.init(trustkeyStore);
    54 
    55         // 初始化SSL上下文
    56         SSLContext ctx = SSLContext.getInstance("SSL");
    57         ctx.init(keyManagerFactory.getKeyManagers(), trustManagerFactory
    58                 .getTrustManagers(), null);
    59         SSLSocketFactory sf = ctx.getSocketFactory();
    60 
    61         HttpsURLConnection.setDefaultSSLSocketFactory(sf);
    62         String url = "https://ssl.demo.com";
    63         URL urlObj = new URL(url);
    64         HttpsURLConnection con = (HttpsURLConnection) urlObj.openConnection();
    65         con.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36");
    66         con.setRequestProperty("Accept-Language", "zh-CN;en-US,en;q=0.5");
    67         con.setRequestMethod("GET");
    68 
    69         String response = readResponseBody(con.getInputStream());
    70         System.out.println(response);
    71     }
    72 
    73     /**
    74      * 获得KeyStore
    75      *
    76      * @param keyStorePath
    77      * @param password
    78      * @return
    79 
    80      * @throws Exception
    81      */
    82     private static KeyStore getKeyStore(String keyStorePath, String password,String type)
    83             throws Exception {
    84         FileInputStream is = new FileInputStream(keyStorePath);
    85         KeyStore ks = KeyStore.getInstance(type);
    86         ks.load(is, password.toCharArray());
    87         is.close();
    88         return ks;
    89     }
    90 
    91 
    92     public static void main(String[] args) throws Exception {
    93         httpsCall();
    94     }
    95 
    96 }

    结果同1。

    3.生成truststore库文件进行访问-Apache HTTP 组件方式

    package me.dreamingodd.ca;
    
    import org.apache.http.client.methods.CloseableHttpResponse;
    import org.apache.http.client.methods.HttpGet;
    import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
    import org.apache.http.impl.client.CloseableHttpClient;
    import org.apache.http.impl.client.HttpClients;
    
    import javax.net.ssl.KeyManagerFactory;
    import javax.net.ssl.SSLContext;
    import javax.net.ssl.TrustManagerFactory;
    import java.io.*;
    import java.net.URI;
    import java.nio.charset.Charset;
    import java.security.KeyStore;
    import java.security.SecureRandom;
    
    /**
     * #3
     * HTTPS 双向认证 - use truststore
     * Apache插件
     * @Author Ye_Wenda
     * @Date 7/11/2017
     */
    public class HttpsTruststoreApacheContextDemo {
        // 客户端证书路径,用了本地绝对路径,需要修改
        private final static String CLIENT_CERT_FILE = "C:/Development/deployment/ssl/ca-demo/client.p12";
        // 客户端证书密码
        private final static String CLIENT_PWD = "demo";
        // 信任库路径
        private final static String TRUST_STRORE_FILE = "C:\Development\deployment\ssl\ca-demo\demo.truststore";
        // 信任库密码
        private final static String TRUST_STORE_PWD = "demodemo";
    
    
        private static String readResponseBody(InputStream inputStream) throws IOException {
            try{
                BufferedReader br = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("UTF-8")));
                StringBuffer sb = new StringBuffer();
                String buff = null;
                while((buff = br.readLine()) != null){
                    sb.append(buff+"
    ");
                }
                return sb.toString();
            }finally{
                inputStream.close();
            }
        }
    
        public static void httpsCall() throws Exception {
            // 初始化密钥库
            KeyManagerFactory keyManagerFactory = KeyManagerFactory
                    .getInstance("SunX509");
            KeyStore keyStore = getKeyStore(CLIENT_CERT_FILE, CLIENT_PWD, "PKCS12");
            keyManagerFactory.init(keyStore, CLIENT_PWD.toCharArray());
    
            // 初始化信任库
            TrustManagerFactory trustManagerFactory = TrustManagerFactory
                    .getInstance("SunX509");
            KeyStore trustkeyStore = getKeyStore(TRUST_STRORE_FILE, TRUST_STORE_PWD,"JKS");
            trustManagerFactory.init(trustkeyStore);
    
    //        SSLContext sslContext = SSLContexts.custom().loadKeyMaterial(keyStore, "123456".toCharArray())
    //            .loadTrustMaterial(new File(TRUST_STRORE_FILE),"012345".toCharArray()).setSecureRandom(new SecureRandom()).useProtocol("SSL").build();
            SSLContext sslContext = SSLContext.getInstance("SSL");
            sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), new SecureRandom());
    
            SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext,new String[]{"TLSv1", "TLSv2", "TLSv3"},null,
                    SSLConnectionSocketFactory.getDefaultHostnameVerifier());
    
            CloseableHttpClient closeableHttpClient = HttpClients.custom().setSSLContext(sslContext).build();
            HttpGet getCall = new HttpGet();
            getCall.setURI(new URI("https://ssl.demo.com"));
            CloseableHttpResponse response = closeableHttpClient.execute(getCall);
            System.out.println(convertStreamToString(response.getEntity().getContent()));
    
        }
    
        public static String convertStreamToString(InputStream is) {
            /*
              * To convert the InputStream to String we use the BufferedReader.readLine()
              * method. We iterate until the BufferedReader return null which means
              * there's no more data to read. Each line will appended to a StringBuilder
              * and returned as String.
              */
            BufferedReader reader = new BufferedReader(new InputStreamReader(is));
            StringBuilder sb = new StringBuilder();
    
            String line = null;
            try {
                while ((line = reader.readLine()) != null) {
                    sb.append(line + "
    ");
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
    
            return sb.toString();
        }
    
        /**
         * 获得KeyStore
         *
         * @param keyStorePath
         * @param password
         * @return
         * @throws Exception
         */
        private static KeyStore getKeyStore(String keyStorePath, String password,String type)
                throws Exception {
            FileInputStream is = new FileInputStream(keyStorePath);
            KeyStore ks = KeyStore.getInstance(type);
            ks.load(is, password.toCharArray());
            is.close();
            return ks;
        }
    
    
    
        public static void main(String[] args) throws Exception {
            httpsCall();
        }
    }

    结果同2。

    本文的相关源码位于 https://github.com/dreamingodd/CA-generation-demo 

    dreamingodd原创文章,如转载请注明出处。

  • 相关阅读:
    elasticserach7.X 安装,配置
    org.elasticsearch.bootstrap.StartupException: ElasticsearchException[failed to bind service]; nested: AccessDeniedException[/home/ae/es761/data/nodes];
    Java 八大基本数据类
    java 输入scanner
    idea生成javaDoc文件
    时间戳和日期的相互转化
    自1970 年1月1日8时0分0秒至当前时间的总秒数什么意思?
    JDK的卸载与JDK的安装以及环境变量配置
    Java特性与优势
    图片识别
  • 原文地址:https://www.cnblogs.com/dreamingodd/p/7491098.html
Copyright © 2020-2023  润新知