美文网首页框架【库】
Retrofit 2.0 + Okhttp 用HTTPS请求

Retrofit 2.0 + Okhttp 用HTTPS请求

作者: Waino_m | 来源:发表于2018-08-09 13:51 被阅读113次

    先说明一下,我的是读取本地资源目录的证书,不是绕过验证,也不是校验服务端证书。

    这是一个很简单的功能,确实。 但是没搞定之前还是难受得丫批。 百度上,简书上的方法都搜过了,用过了,没有用。最后发现是自己不会用(我就知道是这样子的!mmp) 写一篇文章记录一下。希望能够帮到(估计也没有人和我一样弱鸡了)。


    正题开始

    1.因为我们的H5,经常被插入小广告,于是就提议要搞HTTPS,然后申请去了几万,证书下来了(运维老哥给到我们手里)

    证书文件

    然后我看了网上的帖子后缀不一样,我又屁颠屁颠的跑去问了一下。 老哥给我解释了一下crt的全称,然后知道了有人叫crt,有人叫cer。然后我把证书复制到assets目录

    assets目录

    2.然后我开始了双屏CV操作,发现复制过来不能用。然后我朋友建议我去看看OkGo的项目。

    OkGo 

    下载下来看了一下,廖大神有写各种HTTPS的请求方式。真的很全了! 我用的是方法三。

    OkGo HTTPS 请求方式

    3.然后我直接就是把他的这个HttpsUtils方法复制出来了,然后在我自己的请求封装那里加上。

    代码如下:

    请求封装

    Tips:之前有些帖子的证书是放在RAW文件夹里。然后这个地方脑残了一下,没注意getAssets这个方法。 

    然后到这里就结束了。。。。吧?    我都打开网易云放歌了!   然后这个时候APP跑上来,请求出错。。等等。。

    看看Logcat这个东西吧!   请求的地址还是http。 

    这时候想到了点什么,加证书并不会自动给你加S,然后去请求的。

    乖乖的把请求地址加上S。~ 

    放歌吧! 

    放歌请点击:Time

    最后:廖大神的那个“优踢而丝”我放上来吧~

    ```

    /**

    * ================================================

    * 作    者:jeasonlzy(廖子尧)Github地址:https://github.com/jeasonlzy

    * 版    本:1.0

    * 创建日期:16/9/11

    * 描    述:Https相关的工具类

    * 修订历史:

    * ================================================

    */

    public class HttpsUtils {

    public static class SSLParams {

    public SSLSocketFactorysSLSocketFactory;

            public X509TrustManagertrustManager;

        }

    public static SSLParamsgetSslSocketFactory() {

    return getSslSocketFactoryBase(null, null, null);

        }

    /**

    * https单向认证

    * 可以额外配置信任服务端的证书策略,否则默认是按CA证书去验证的,若不是CA可信任的证书,则无法通过验证

    */

        public static SSLParamsgetSslSocketFactory(X509TrustManager trustManager) {

    return getSslSocketFactoryBase(trustManager, null, null);

        }

    /**

    * https单向认证

    * 用含有服务端公钥的证书校验服务端证书

    */

        public static SSLParamsgetSslSocketFactory(InputStream... certificates) {

    return getSslSocketFactoryBase(null, null, null, certificates);

        }

    /**

    * https双向认证

    * bksFile 和 password -> 客户端使用bks证书校验服务端证书

    * certificates -> 用含有服务端公钥的证书校验服务端证书

    */

        public static SSLParamsgetSslSocketFactory(InputStream bksFile, String password, InputStream... certificates) {

    return getSslSocketFactoryBase(null, bksFile, password, certificates);

        }

    /**

    * https双向认证

    * bksFile 和 password -> 客户端使用bks证书校验服务端证书

    * X509TrustManager -> 如果需要自己校验,那么可以自己实现相关校验,如果不需要自己校验,那么传null即可

    */

        public static SSLParamsgetSslSocketFactory(InputStream bksFile, String password, X509TrustManager trustManager) {

    return getSslSocketFactoryBase(trustManager, bksFile, password);

        }

    private static SSLParamsgetSslSocketFactoryBase(X509TrustManager trustManager, InputStream bksFile, String password, InputStream... certificates) {

    SSLParams sslParams =new SSLParams();

            try {

    KeyManager[] keyManagers =prepareKeyManager(bksFile, password);

                TrustManager[] trustManagers =prepareTrustManager(certificates);

                X509TrustManager manager;

                if (trustManager !=null) {

    //优先使用用户自定义的TrustManager

                    manager = trustManager;

                }else if (trustManagers !=null) {

    //然后使用默认的TrustManager

                    manager =chooseTrustManager(trustManagers);

                }else {

    //否则使用不安全的TrustManager

                    manager =UnSafeTrustManager;

                }

    // 创建TLS类型的SSLContext对象, that uses our TrustManager

                SSLContext sslContext = SSLContext.getInstance("TLS");

                // 用上面得到的trustManagers初始化SSLContext,这样sslContext就会信任keyStore中的证书

    // 第一个参数是授权的密钥管理器,用来授权验证,比如授权自签名的证书验证。第二个是被授权的证书管理器,用来验证服务器端的证书

                sslContext.init(keyManagers, new TrustManager[]{manager}, null);

                // 通过sslContext获取SSLSocketFactory对象

                sslParams.sSLSocketFactory = sslContext.getSocketFactory();

                sslParams.trustManager = manager;

                return sslParams;

            }catch (NoSuchAlgorithmException e) {

    throw new AssertionError(e);

            }catch (KeyManagementException e) {

    throw new AssertionError(e);

            }

    }

    private static KeyManager[]prepareKeyManager(InputStream bksFile, String password) {

    try {

    if (bksFile ==null || password ==null)return null;

                KeyStore clientKeyStore = KeyStore.getInstance("BKS");

                clientKeyStore.load(bksFile, password.toCharArray());

                KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());

                kmf.init(clientKeyStore, password.toCharArray());

                return kmf.getKeyManagers();

            }catch (Exception e) {

    e.printStackTrace();

            }

    return null;

        }

    private static TrustManager[]prepareTrustManager(InputStream... certificates) {

    if (certificates ==null || certificates.length <=0)return null;

            try {

    CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");

                // 创建一个默认类型的KeyStore,存储我们信任的证书

                KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());

                keyStore.load(null);

                int index =0;

                for (InputStream certStream : certificates) {

    String certificateAlias = Integer.toString(index++);

                    // 证书工厂根据证书文件的流生成证书 cert

                    Certificate cert = certificateFactory.generateCertificate(certStream);

                    // 将 cert 作为可信证书放入到keyStore中

                    keyStore.setCertificateEntry(certificateAlias, cert);

                    try {

    if (certStream !=null) certStream.close();

                    }catch (IOException e) {

    e.printStackTrace();

                    }

    }

    //我们创建一个默认类型的TrustManagerFactory

                TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());

                //用我们之前的keyStore实例初始化TrustManagerFactory,这样tmf就会信任keyStore中的证书

                tmf.init(keyStore);

                //通过tmf获取TrustManager数组,TrustManager也会信任keyStore中的证书

                return tmf.getTrustManagers();

            }catch (Exception e) {

    e.printStackTrace();

            }

    return null;

        }

    private static X509TrustManagerchooseTrustManager(TrustManager[] trustManagers) {

    for (TrustManager trustManager : trustManagers) {

    if (trustManagerinstanceof X509TrustManager) {

    return (X509TrustManager) trustManager;

                }

    }

    return null;

        }

    /**

    * 为了解决客户端不信任服务器数字证书的问题,网络上大部分的解决方案都是让客户端不对证书做任何检查,

    * 这是一种有很大安全漏洞的办法

    */

        public static X509TrustManagerUnSafeTrustManager =new X509TrustManager() {

    @Override

            public void checkClientTrusted(X509Certificate[] chain, String authType)throws CertificateException {

    }

    @Override

            public void checkServerTrusted(X509Certificate[] chain, String authType)throws CertificateException {

    }

    @Override

            public X509Certificate[]getAcceptedIssuers() {

    return new X509Certificate[]{};

            }

    };

        /**

    * 此类是用于主机名验证的基接口。 在握手期间,如果 URL 的主机名和服务器的标识主机名不匹配,

    * 则验证机制可以回调此接口的实现程序来确定是否应该允许此连接。策略可以是基于证书的或依赖于其他验证方案。

    * 当验证 URL 主机名使用的默认规则失败时使用这些回调。如果主机名是可接受的,则返回 true

    */

        public static HostnameVerifierUnSafeHostnameVerifier =new HostnameVerifier() {

    @Override

            public boolean verify(String hostname, SSLSession session) {

    return true;

            }

    };

    }

    ```

    相关文章

      网友评论

        本文标题:Retrofit 2.0 + Okhttp 用HTTPS请求

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