溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Android開(kāi)發(fā) - Retrofit 2 使用自簽名的HTTPS證書(shū)進(jìn)行API請(qǐng)求

發(fā)布時(shí)間:2020-07-19 15:11:11 來(lái)源:網(wǎng)絡(luò) 閱讀:1508 作者:羅伊德666 欄目:移動(dòng)開(kāi)發(fā)

為了確保數(shù)據(jù)傳輸?shù)陌踩?,現(xiàn)在越來(lái)越多的應(yīng)用使用Https的方式來(lái)進(jìn)行數(shù)據(jù)傳輸,使用https有很多有點(diǎn),比如:

  • HTTPS協(xié)議是由SSL+HTTP協(xié)議構(gòu)建的可進(jìn)行加密傳輸、身份認(rèn)證的網(wǎng)絡(luò)協(xié)議,要比http協(xié)議安全,可防止數(shù)據(jù)在傳輸過(guò)程中不被竊取、改變,確保數(shù)據(jù)的完整性。
  • HTTPS是現(xiàn)行架構(gòu)下最安全的解決方案,雖然不是絕對(duì)安全,但它大幅增加了中間人***的成本。

但是即使使用HTTPS有很多有點(diǎn),但是購(gòu)買一個(gè)認(rèn)證的HTTPS證書(shū)卻價(jià)格不菲,增加了初創(chuàng)企業(yè)和小團(tuán)隊(duì)的開(kāi)發(fā)成本。而且如上面所說(shuō),使用HTTPS并非絕對(duì)的安全,傳輸?shù)臄?shù)據(jù)并非沒(méi)有辦法獲取到,我的之前一篇博客所使用的方法已成功截取HTTPS的數(shù)據(jù)傳輸。有興趣的可以參考:使用Charles對(duì)Android App的https請(qǐng)求進(jìn)行抓包。

為了節(jié)約成本,我們可以選擇使用自簽名的HTTPS。
這種方式我們可以自己生成證書(shū),不需要購(gòu)買證書(shū),但是使用這種方式的域名如果在瀏覽器中訪問(wèn)的話,會(huì)有一個(gè)不安全的標(biāo)識(shí)。但是如果用在客戶端上,就不會(huì)有這個(gè)問(wèn)題,現(xiàn)在一些應(yīng)用商店也要求APP上架時(shí)需要使用HTTPS的網(wǎng)絡(luò)請(qǐng)求(比如AppStore),使用這種自簽名的HTTPS同樣也能過(guò)審。

本文我們介紹在Android上使用網(wǎng)絡(luò)請(qǐng)求框架Retrofit 2來(lái)請(qǐng)求自簽名的API,關(guān)于如何生成HTTPS證書(shū),我們將在另一篇博客中進(jìn)行說(shuō)明,敬請(qǐng)期待?;蛘吣梢宰孕胁檎蚁嚓P(guān)資料。

配置證書(shū)

比如我們生成的SLL證書(shū)文件為"api_ssl_debug.cer",我們將其放到assets目錄下。這樣在配置Retrofit的時(shí)候就可以讀取該證書(shū)并用于API請(qǐng)求中。

配置Retrofit

本節(jié)我們介紹SSL證書(shū)在Retrofit中的配置,首先我們要定義兩個(gè)方法用來(lái)讀取證書(shū),然后講該證書(shū)用于Retrofit中。

  1. 讀取證書(shū)內(nèi)容到KeyStore中
    private static KeyStore getKeyStore(String fileName) {
        KeyStore keyStore = null;
        try {
            AssetManager assetManager = Utils.getApp().getAssets();
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
            InputStream caInput = assetManager.open(fileName);
            Certificate ca;
            try {
                ca = cf.generateCertificate(caInput);
                Log.d("SslUtils", "ca=" + ((X509Certificate) ca).getSubjectDN());
            } finally {
                caInput.close();
            }

            String keyStoreType = KeyStore.getDefaultType();
            keyStore = KeyStore.getInstance(keyStoreType);
            keyStore.load(null, null);
            keyStore.setCertificateEntry("ca", ca);
        } catch (Exception e) {
            Log.e("SslUtils", "Error during getting keystore", e);
        }
        return keyStore;
    }
  1. 生成SSLContext以便用于Retrofit的配置中
    public static SSLContext getSslContextForCertificateFile(String fileName) {
        try {
            KeyStore keyStore = SslUtils.getKeyStore(fileName);
            SSLContext sslContext = SSLContext.getInstance("SSL");
            TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            trustManagerFactory.init(keyStore);
            sslContext.init(null, trustManagerFactory.getTrustManagers(), new SecureRandom());
            return sslContext;
        } catch (Exception e) {
            String msg = "Error during creating SslContext for certificate from assets";
            Log.e("SslUtils", msg, e);
            throw new RuntimeException(msg);
        }
    }
  1. 配置Retrofit
SSLContext sslContext = SslUtils.getSslContextForCertificateFile("api_ssl_debug.cer");

TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(
                TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init((KeyStore) null);
TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {
    throw new IllegalStateException("Unexpected default trust managers:"
                    + Arrays.toString(trustManagers));
}
X509TrustManager trustManager = (X509TrustManager) trustManagers[0];

OkHttpClient.Builder builder = new OkHttpClient.Builder()
                ...
                .sslSocketFactory(sslContext.getSocketFactory(), trustManager)
                .hostnameVerifier((hostname, session) -> true)
                ...

mRetrofit = new Retrofit.Builder()
                ...
                build();

以上的省略號(hào)為Retrofit的其它配置,可以根據(jù)工程需要進(jìn)行配置。

總結(jié)

至此,使用Retrofit就可以進(jìn)行自簽名的HTTPS的網(wǎng)絡(luò)請(qǐng)求了,當(dāng)然,服務(wù)器端的API配置也需要進(jìn)行HTTPS的配置,我將在服務(wù)端相關(guān)的博客進(jìn)行介紹,還有一點(diǎn),如果請(qǐng)求的域名指定了端口,要將端口設(shè)置為443。如果沒(méi)有指定端口,請(qǐng)求時(shí)也會(huì)自動(dòng)走443端口。

本文原始地址,如有更多疑問(wèn),請(qǐng)參考我的其它Android相關(guān)博客:我的博客地址

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI