美文网首页Net
Android使用OkHttp访问自签名证书的Https接口

Android使用OkHttp访问自签名证书的Https接口

作者: Shawpoo的 | 来源:发表于2017-06-02 15:39 被阅读392次

    转载请注明出处:http://www.jianshu.com/p/37a73df2146a
    本文出自Shawpoo的简书
    我的博客:CSDN博客

    前言

    在Android开发中,Okhttp想必大家都不陌生,一个处理网络请求的开源项目,是安卓端最火热的轻量级框架。

    本人在开发过程中也用了很长一段时间了,但是基本请求的都是http接口。即使访问https网站也都是绿色的,有个很特殊的大型购票网站则不是,所以本文主要介绍如何使用Okhttp访问自签名证书的https接口。而且公司自己服务接口也全部换成了https接口,在去年就说ios要强制更换https接口,不然appstore无法上架,最近好像也没信了,估计是政策放宽了吧。不管怎样,今天就拿这个大型购票网站举例来说,使用Okhttp访问购票网站。

    获取签名证书

    购票网站的签名证书可以在官网上直接下载,或者点击这里下载即可。srca.cer即为购票网站的签名证书。

    为了方便将签名证书添加到OkHttp中,可以将签名证书放在本地的assets文件夹下,为了便于管理我放在了assets/cers目录下,在代码中可以通过流的形式获取到证书文件。

    添加证书一般是在访问接口之前添加,为了方便,我放在了Application中,这样的话,在应用启动的时候就会已经将添加添加到了OkHttp中。

    使用Okhttp访问接口

    • 使用Android Studio的话,直接添加Okhttp的依赖:
    compile 'com.squareup.okhttp3:okhttp:3.3.1'
    
    
    • 获取签名证书文件流
    //获取证书流
    private void readHttpsCer() {
            try {
                InputStream is = getAssets().open("cers/srca.cer");
                NetConfig.addCertificate(is); // 这里将证书读取出来,,放在配置中byte[]里
            } catch (IOException ioe) {
                ioe.printStackTrace();
            }
        }
    
    • NetConfig相关代码:
    // 证书数据
        private static List<byte[]> CERTIFICATES_DATA = new ArrayList<>();
    
        /**
         * 添加https证书
         *
         * @param inputStream
         */
        public synchronized static void addCertificate(InputStream inputStream) {
            Log.i(TAG, "#addCertificate inputStream = " + inputStream);
            if (inputStream != null) {
    
                try {
                    int ava = 0;// 数据当次可读长度
                    int len = 0;// 数据总长度
                    ArrayList<byte[]> data = new ArrayList<>();
                    while ((ava = inputStream.available()) > 0) {
                        byte[] buffer = new byte[ava];
                        inputStream.read(buffer);
                        data.add(buffer);
                        len += ava;
                    }
    
                    byte[] buff = new byte[len];
                    int dstPos = 0;
                    for (byte[] bytes : data) {
                        int length = bytes.length;
                        System.arraycopy(bytes, 0, buff, dstPos, length);
                        dstPos += length;
                    }
    
                    CERTIFICATES_DATA.add(buff);
                } catch (IOException e) {
                    e.printStackTrace();
                }
    
            }
        }
    
        /**
         * https证书
         *
         * @return
         */
        public static List<byte[]> getCertificatesData() {
            return CERTIFICATES_DATA;
        }
    
    
    • 编写工具类,将证书添加到OkHttp中:
     public static OkHttpClient createOkHttp() {
    
            OkHttpClient.Builder builder = new OkHttpClient.Builder();
            // 添加证书
            List<InputStream> certificates = new ArrayList<>();
            List<byte[]> certs_data = NetConfig.getCertificatesData();
    
            // 将字节数组转为数组输入流
            if (certs_data != null && !certs_data.isEmpty()) {
                for (byte[] bytes : certs_data) {
                    certificates.add(new ByteArrayInputStream(bytes));
                }
            }
    
    
            SSLSocketFactory sslSocketFactory = getSocketFactory(certificates);
            if (sslSocketFactory != null) {
                builder.sslSocketFactory(sslSocketFactory);
            }
    
            return builder.build();
        }
    
    
        /**
         * 添加证书
         *
         * @param certificates
         */
        private static SSLSocketFactory getSocketFactory(List<InputStream> certificates) {
            try {
                CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
                KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
                keyStore.load(null);
                try {
                    for (int i = 0, size = certificates.size(); i < size; ) {
                        InputStream certificate = certificates.get(i);
                        String certificateAlias = Integer.toString(i++);
                        keyStore.setCertificateEntry(certificateAlias, certificateFactory
                                .generateCertificate(certificate));
                        if (certificate != null)
                            certificate.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
    
                SSLContext sslContext = SSLContext.getInstance("TLS");
                TrustManagerFactory trustManagerFactory =
                        TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
                trustManagerFactory.init(keyStore);
                sslContext.init(null, trustManagerFactory.getTrustManagers(), new SecureRandom());
                return sslContext.getSocketFactory();
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }
    
    
    • 查看测试使用结果:

    将自签名证书添加到Okhttp中,通过创建的OkHttpClient对象,我们就可以访问相关的Https接口服务了。

    点击下载Demo

    参考阅读

    Okhttp官网
    Okhttp on Github

    相关文章

      网友评论

        本文标题:Android使用OkHttp访问自签名证书的Https接口

        本文链接:https://www.haomeiwen.com/subject/bqhgnttx.html