Https系列之四:https的SSL證書在Android端基于okhttp徙鱼,Retrofit的使用

先來回顧一下

前面已分別介紹了https,SSL證書的生成宅楞,并完成了服務(wù)器端的https的部署 针姿,并提到一個重要的用于客戶端的證書:公鑰證書

在前面文章中,自簽名SSL證書對應(yīng)的公鑰證書為:mycer.cer(當然這名字是自己隨便定的)厌衙。在阿里云申請的CA證書中對應(yīng)的公鑰證書為:*.pem
如果有不清楚的距淫,請看我之前介紹過的文章

Android自帶的可信任的CA公鑰證書

還要說明一下,Android系統(tǒng)有自帶的安卓認可的證書頒發(fā)機構(gòu)(如:Wosign)頒發(fā)的可信任的CA公鑰證書婶希,大概有100多個榕暇, 可自己查看,各個手機的查看方法可能不一樣喻杈,在我的手機中彤枢,能在下面的位置中找到: “設(shè)置”->”更多設(shè)置“->”系統(tǒng)安全“->”信任的憑據(jù)”

也就是說,如果你服務(wù)器的證書是安卓認可的證書頒發(fā)機構(gòu)頒發(fā)的筒饰,那么你并不需要在Android端額外安裝公鑰證書缴啡,否則,你就需要安裝瓷们。

注:在不同版本的Android系統(tǒng)上业栅,可信任的CA證書可能是不一樣的,如果你擔心在別人的Android系統(tǒng)上可能此CA證書不被信任谬晕,那你統(tǒng)一都安裝也是沒問題的

我在阿里云上申請的免費型DV SSL證書碘裕,是屬于安卓認可的證書頒發(fā)機構(gòu)頒發(fā)的,不需要額外安裝固蚤,當然我們的自簽名證書娘汞,是必需要安裝的

其實我在測試的過程中,把自簽名證書和阿里云上申請的免費型DV SSL證書都用同樣的方法安裝了夕玩,都是OK的

我們下面就開始基于okhttp來安裝公鑰證書了

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

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

增加一個OkhttpManager類

統(tǒng)一處理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)

把自己的證書對應(yīng)的文件set進去燎孟,然后通過

trustManager =trustManagerForCertificates(getTrustrCertificates());

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

就能生成安裝好了可信任證書的okHttpClient
OkhttpManager說完了禽作,接下來,就是:

Activity中使用OkhttpManager

  1. 先把公鑰證書文件(如:自簽名的mycer.cer或CA證書的:*.pem)放到assets下揩页,
    如果使用AndroidStudio的同學(xué)旷偿,可能沒有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怎樣使用茫负,大家都應(yīng)該清楚了吧,如果不清楚只能看OkHttpClient的基礎(chǔ)內(nèi)容了

接下來就到Retrofit了

大家應(yīng)該知到Retrofit默認是以O(shè)kHttpClient來作為傳輸?shù)暮醺埃热籓kHttpClient搞掂了忍法,那Retrofit就簡單了
還是直接貼代碼:

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

看潮尝,只需在Retrofit中多加一句

.client(mOkhttpClient)

就把已安裝了證書的mOkhttpClient作為Retrofit的傳輸了

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市饿序,隨后出現(xiàn)的幾起案子勉失,更是在濱河造成了極大的恐慌,老刑警劉巖原探,帶你破解...
    沈念sama閱讀 218,941評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件乱凿,死亡現(xiàn)場離奇詭異,居然都是意外死亡咽弦,警方通過查閱死者的電腦和手機告匠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來离唬,“玉大人,你說我怎么就攤上這事划鸽∈漭海” “怎么了?”我有些...
    開封第一講書人閱讀 165,345評論 0 356
  • 文/不壞的土叔 我叫張陵裸诽,是天一觀的道長嫂用。 經(jīng)常有香客問我,道長丈冬,這世上最難降的妖魔是什么嘱函? 我笑而不...
    開封第一講書人閱讀 58,851評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮埂蕊,結(jié)果婚禮上往弓,老公的妹妹穿的比我還像新娘。我一直安慰自己蓄氧,他們只是感情好函似,可當我...
    茶點故事閱讀 67,868評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著喉童,像睡著了一般撇寞。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上堂氯,一...
    開封第一講書人閱讀 51,688評論 1 305
  • 那天蔑担,我揣著相機與錄音,去河邊找鬼咽白。 笑死啤握,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的局扶。 我是一名探鬼主播恨统,決...
    沈念sama閱讀 40,414評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼叁扫,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了畜埋?” 一聲冷哼從身側(cè)響起莫绣,我...
    開封第一講書人閱讀 39,319評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎悠鞍,沒想到半個月后对室,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,775評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡咖祭,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年掩宜,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片么翰。...
    茶點故事閱讀 40,096評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡牺汤,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出浩嫌,到底是詐尸還是另有隱情檐迟,我是刑警寧澤,帶...
    沈念sama閱讀 35,789評論 5 346
  • 正文 年R本政府宣布码耐,位于F島的核電站追迟,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏骚腥。R本人自食惡果不足惜敦间,卻給世界環(huán)境...
    茶點故事閱讀 41,437評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望束铭。 院中可真熱鬧廓块,春花似錦、人聲如沸契沫。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽埠褪。三九已至浓利,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間钞速,已是汗流浹背贷掖。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留渴语,地道東北人苹威。 一個月前我還...
    沈念sama閱讀 48,308評論 3 372
  • 正文 我出身青樓,卻偏偏與公主長得像驾凶,于是被迫代替她去往敵國和親牙甫。 傳聞我的和親對象是個殘疾皇子掷酗,可洞房花燭夜當晚...
    茶點故事閱讀 45,037評論 2 355

推薦閱讀更多精彩內(nèi)容