zoukankan      html  css  js  c++  java
  • Https系列之四:https的SSL证书在Android端基于okhttp,Retrofit的使用

    Https系列会在下面几篇文章中分别作介绍:

    一:https的简单介绍及SSL证书的生成
    二:https的SSL证书在服务器端的部署,基于tomcat,spring boot
    三:让服务器同时支持http、https,基于spring boot
    四:https的SSL证书在Android端基于okhttp,Retrofit的使用

    所有文章会优先在:
    微信公众号“颜家大少”中发布
    转载请标明出处


    先来回顾一下

    前面已分别介绍了https,SSL证书的生成,并完成了服务器端的https的部署
    并提到一个重要的用于客户端的证书:公钥证书
    在前面文章中,自签名SSL证书对应的公钥证书为:mycer.cer(当然这名字是自己随便定的);在阿里云申请的CA证书中对应的公钥证书为:*.pem
    如果有不清楚的,请看我之前介绍过的文章

    Android自带的可信任的CA公钥证书

    还要说明一下,Android系统有自带的安卓认可的证书颁发机构(如:Wosign)颁发的可信任的CA公钥证书,大概有100多个,
    可自己查看,各个手机的查看方法可能不一样,在我的手机中,能在下面的位置中找到:
    “设置”->”更多设置“->”系统安全“->”信任的凭据”
    也就是说,如果你服务器的证书是安卓认可的证书颁发机构颁发的,那么你并不需要在Android端额外安装公钥证书,否则,你就需要安装。
    注:在不同版本的Android系统上,可信任的CA证书可能是不一样的,如果你担心在别人的Android系统上可能此CA证书不被信任,那你统一都安装也是没问题的
    我在阿里云上申请的免费型DV SSL证书,是属于安卓认可的证书颁发机构颁发的,不需要额外安装,当然我们的自签名证书,是必需要安装的
    其实我在测试的过程中,把自签名证书和阿里云上申请的免费型DV SSL证书都用同样的方法安装了,都是OK的

    我们下面就开始基于okhttp来安装公钥证书了

    先看看我的okhttp和retrofit的gradle版本

    compile 'com.squareup.okhttp3:okhttp:3.8.1'
    compile 'com.squareup.retrofit2:retrofit:2.3.0'
    

    增加一个OkhttpManager类

    统一处理OkHttpClient的证书,完整的代码如下:

    import android.content.Context;
    import java.io.IOException;
    import java.io.InputStream;
    import java.security.GeneralSecurityException;
    import java.security.KeyStore;
    import java.security.cert.Certificate;
    import java.security.cert.CertificateFactory;
    import java.util.Arrays;
    import java.util.Collection;
    import javax.net.ssl.KeyManagerFactory;
    import javax.net.ssl.SSLContext;
    import javax.net.ssl.SSLSocketFactory;
    import javax.net.ssl.TrustManager;
    import javax.net.ssl.TrustManagerFactory;
    import javax.net.ssl.X509TrustManager;
    import okhttp3.OkHttpClient;
    
    public class OkhttpManager {
        static private OkhttpManager mOkhttpManager=null;
        private InputStream mTrustrCertificate;
        static public OkhttpManager getInstance()
        {
            if(mOkhttpManager==null)
            {
                mOkhttpManager=new OkhttpManager();
            }
            return mOkhttpManager;
        }
    
        private KeyStore newEmptyKeyStore(char[] password) throws GeneralSecurityException {
            try {
                KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
                InputStream in = null; // By convention, 'null' creates an empty key store.
                keyStore.load(in, password);
                return keyStore;
            } catch (IOException e) {
                throw new AssertionError(e);
            }
        }
    
        private X509TrustManager trustManagerForCertificates(InputStream in)
                throws GeneralSecurityException {
            CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
            Collection<? extends Certificate> certificates = certificateFactory.generateCertificates(in);
            if (certificates.isEmpty()) {
                throw new IllegalArgumentException("expected non-empty set of trusted certificates");
            }
    
            // Put the certificates a key store.
            char[] password = "password".toCharArray(); // Any password will work.
            KeyStore keyStore = newEmptyKeyStore(password);
            int index = 0;
            for (Certificate certificate : certificates) {
                String certificateAlias = Integer.toString(index++);
                keyStore.setCertificateEntry(certificateAlias, certificate);
            }
    
            // Use it to build an X509 trust manager.
            KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
            keyManagerFactory.init(keyStore, password);
            TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            trustManagerFactory.init(keyStore);
            TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
            if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {
                throw new IllegalStateException("Unexpected default trust managers:" + Arrays.toString(trustManagers));
            }
            return (X509TrustManager) trustManagers[0];
        }
    
        public void setTrustrCertificates(InputStream in)
        {
            mTrustrCertificate=in;
        }
    
        public InputStream getTrustrCertificates()
        {
            return mTrustrCertificate;
        }
    
        public OkHttpClient build()
        {
            OkHttpClient okHttpClient=null;
            if(getTrustrCertificates()!=null)
            {
                X509TrustManager trustManager;
                SSLSocketFactory sslSocketFactory;
                try {
                    trustManager = trustManagerForCertificates(getTrustrCertificates());
                    SSLContext sslContext = SSLContext.getInstance("TLS");
                    sslContext.init(null, new TrustManager[] { trustManager }, null);
                    sslSocketFactory = sslContext.getSocketFactory();
                } catch (GeneralSecurityException e) {
                    throw new RuntimeException(e);
                }
                okHttpClient=new OkHttpClient.Builder()
                        .sslSocketFactory(sslSocketFactory, trustManager)
                        .build();
            }
            else
            {
                okHttpClient=new OkHttpClient.Builder()
                                             .build();
            }
            return okHttpClient;
        }
    
    }
    

    代码解释

    代码不少,其实最核心的代码为:

    public OkHttpClient build()
    {
    .......
     trustManager = trustManagerForCertificates(getTrustrCertificates());
     .......
      okHttpClient=new OkHttpClient.Builder()
                        .sslSocketFactory(sslSocketFactory, trustManager)
                        .build();
     ..........
     return okHttpClient;
    }
    

    也就是通过

    void setTrustrCertificates(InputStream in)
    

    把自己的证书对应的文件set进去

    然后通过

    trustManager =trustManagerForCertificates(getTrustrCertificates());
    

    okHttpClient=new OkHttpClient.Builder()
                        .sslSocketFactory(sslSocketFactory, trustManager)
                        .build();
    

    就能生成安装好了可信任证书的okHttpClient

    OkhttpManager说完了,接下来,就是:

    Activity中使用OkhttpManager

    1:先把公钥证书文件(如:自签名的mycer.cer或CA证书的:*.pem)放到assets下,
    如果使用AndroidStudio的同学,可能没有assets文件夹,自己建此文件夹,如我的为:app\src\main\assets

    2:直接贴Activity主要的代码:

    public class MyActivity extends AppCompatActivity {
    @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
           super.onCreate(savedInstanceState);
           try {
                OkhttpManager.getInstance().setTrustrCertificates(getAssets().open("mycer.cer");
                OkHttpClient mOkhttpClient= OkhttpManager.getInstance().build();
            } catch (IOException e) {
                e.printStackTrace();
            }
    }
    

    简单吧,主要代码就那两句,就生成了已安装公钥证书”mycer.cer”的mOkhttpClient
    接下来的mOkhttpClient怎样使用,大家都应该清楚了吧,如果不清楚只能看OkHttpClient的基础内容了

    好了,OkHttpClient搞掂了

    接下来就到Retrofit了

    大家应该知到Retrofit默认是以OkHttpClient来作为传输的,既然OkHttpClient搞掂了,那Retrofit就简单了
    还是直接贴代码:

     Retrofit retrofit = new Retrofit.Builder()
                    .client(mOkhttpClient)
                    .baseUrl("your_serverl_url")
                    .build();
    

    看,只需在Retrofit中多加一句

    .client(mOkhttpClient)
    

    就把已安装了证书的mOkhttpClient作为Retrofit的传输了


    更多内容,请关注微信公众号:颜家大少
    这里写图片描述

  • 相关阅读:
    大数据揭秘华尔街如何从金融危机中赚钱
    大数据揭秘华尔街如何从金融危机中赚钱
    CDA考试 ▏2017 CDA L1备考资源习题详解-统计基础部分
    CDA考试 ▏2017 CDA L1备考资源习题详解-统计基础部分
    同步大数据发展与大数据法制,方能形成一个良性循环
    同步大数据发展与大数据法制,方能形成一个良性循环
    Solr在Linux中的安装
    NOSQL中的redis缓存数据库
    Context initialization failed
    Caused by: java.sql.SQLException: Field 'category_id' doesn't have a default value
  • 原文地址:https://www.cnblogs.com/garyyan/p/7605097.html
Copyright © 2011-2022 走看看