Android結合Retrofit實現統一加解密處理(Get、Post、Delete、Put)

Android中對接口進行統一加密

在之前的博客中我們介紹了 加密方案的選擇Android中加解密需要注意的地方

本篇博客我們主要來看一下Android結合Retrofit進行加解密時的注意事項。

在開發過程中,接口是很多的,我們不可能分別對每個接口的請求數據都進行加密,這樣寫起來以及後期維護是非常麻煩的,所以,肯定要是統一處理的
還有我們常用的GetPostDeletePut請求他們的請求數據存放位置是不一樣的,所以,我們需要對不同的請求方式做處理。
上傳文件時,一般是不需要加密的,還有通過Retrofit請求第三方接口時也是不需要加密的,這些我們都需要考慮到。

目前來講,我們最常使用的網絡請求框架就是Retrofit了,Retrofit實際上就是對OkHttp的封裝,網上的一些博客對加解密的處理是在轉換器中處理的,實際上我認爲這種方式並不好,首先我們來看一下GsonConverterFactory的源碼.
在這裏插入圖片描述
看過源碼你會發現,轉換器只能對響應體和請求體進行處理,解密的時候還好說,加密的時候如果你使用的是Get或者Delete這中請求方式時,轉換器是不好進行處理的。所以,關於Retrofit的統一加解密還是建議在攔截器中進行處理。

下面我們來總結一下注意事項:

  • 加解密要統一進行處理,方便維護
  • 加密時要對不同的加密方式進行不同的加密處理
  • 第三方接口,不加密
  • 上傳時不加密

Retrofit 統一加密攔截器

攔截器對請求數據加密流程

  1. 獲取請求的數據
  2. 對請求數據進行加密
  3. 根據不同的請求方式構造新的request

由於加密的相關邏輯需要跟後臺商量,下面代碼主要是看實現邏輯和注意事項,具體加密方法根據自身情況進行修改。
加密方案的選擇可以看博客開始給的連接去選擇。

/**
 * @description: 對請求數據進行加密處理
 * @author : yzq
 * @date   : 2019/3/16
 * @time   : 16:37
 *
 */

class RequestEncryptInterceptor : Interceptor {
    override fun intercept(chain: Interceptor.Chain): Response {
        var request = chain.request()
        var charset = Charset.forName("UTF-8")
        val method = request.method().toLowerCase().trim()

        val url = request.url()
        /*本次請求的接口地址*/
        val apiPath = "${url.scheme()}://${url.host()}:${url.port()}${url.encodedPath()}".trim()
        /*服務端的接口地址*/
        val serverPath = "${url.scheme()}://${url.host()}/".trim()
        /*如果請求的不是服務端的接口,不加密*/
        if (!serverPath.startsWith(ServerConstants.getServerUrl())) {
            return chain.proceed(request)
        }

        /*如果請求方式是Get或者Delete,此時請求數據是拼接在請求地址後面的*/
        if (method.equals("get") || method.equals("delete")) {

            /*如果有請求數據 則加密*/
            if (url.encodedQuery() != null) {
                try {
                    val queryparamNames = request.url().encodedQuery()
                    val encryptqueryparamNames=“這裏調用加密的方法,自行修改”
             		//拼接加密後的url,參數字段自己跟後臺商量,這裏我用param,後臺拿到數據先對param進行解密,解密後的數據就是請求的數據
                    val newUrl = "$apiPath?param=$encryptqueryparamNames"
                    //構建新的請求
                    request = request.newBuilder().url(newUrl ).build()
                } catch (e: Exception) {
                    e.printStackTrace()
                    return chain.proceed(request)
                }
            }
        } else {
        	//不是Get和Delete請求時,則請求數據在請求體中
            val requestBody = request.body()

            /*判斷請求體是否爲空  不爲空則執行以下操作*/
            if (requestBody != null) {
                val contentType = requestBody.contentType()
                if (contentType != null) {
                    charset = contentType.charset(charset)
                    /*如果是二進制上傳  則不進行加密*/
                    if (contentType.type().toLowerCase().equals("multipart")) {                     
                        return chain.proceed(request)
                    }
                }

                /*獲取請求的數據*/
                try {
                    val buffer = Buffer()
                    requestBody.writeTo(buffer)
                    val requestData = URLDecoder.decode(buffer.readString(charset).trim(), "utf-8")

                 	val encryptData=“這裏調用加密的方法,自行修改”
                    /*構建新的請求體*/
                    val newRequestBody = RequestBody.create(contentType, encryptData)

                    /*構建新的requestBuilder*/
                    val newRequestBuilder = request.newBuilder()
                    //根據請求方式構建相應的請求
                    when (method) {
                        "post" -> newRequestBuilder.post(newRequestBody)
                        "put" -> newRequestBuilder.put(newRequestBody)
                    }
                    request = newRequestBuilder.build()

                } catch (e: Exception) {
                    LogUtils.e("加密異常====》${e}")
                    return chain.proceed(request)
                }
            }
        }
        return chain.proceed(request)
    }
}

好了,加密攔截器基本就是這樣


Retrofit 統一解密攔截器

解密就簡單跟多了,直接處理相應體即可,下面是參考代碼

/**
 * @description: 對響應數據進行解密
 * @author : yzq
 * @date   : 2019/3/20
 * @time   : 16:13
 *
 */

class ResponseDecryptInterceptor : Interceptor {

    override fun intercept(chain: Interceptor.Chain): Response {

        val request = chain.request()
        var response = chain.proceed(request)

        if (response.isSuccessful) {
            val responseBody = response.body()
            if (esponseBody != null) {
                /*開始解密*/
                try {
                    val source = responseBody.source()
                    source.request(java.lang.Long.MAX_VALUE)
                    val buffer = source.buffer()
                    var charset = Charset.forName("UTF-8")
                    val contentType = responseBody.contentType()
                    if (contentType != null) {
                        charset = contentType.charset(charset)
                    }
                    val bodyString = buffer.clone().readString(charset)        
                    val responseData = “這裏調解密的方法”                  
                    /*將解密後的明文返回*/
                    val newResponseBody = ResponseBody.create(contentType, responseData.trim())
                    response = response.newBuilder().body(newResponseBody).build()
                } catch (e: Exception) {
                    /*異常說明解密失敗 信息被篡改 直接返回即可 */
                    LogUtils.e("解密異常====》${e}")
                    return response
                }
            } else {
                LogUtils.i("響應體爲空")
            }
        }
        return response

    }
}

好了,解密攔截器就完成了。


加解密攔截器寫好之後添加到okHttp中即可。

        val okHttpBuilder = OkHttpClient.Builder()
            .addInterceptor(RequestHeadersInterceptor())
            .addInterceptor(RequestEncryptInterceptor())
            .addInterceptor(initLogInterceptor())
            .addInterceptor(ResponseDecryptInterceptor())
            .build()

然後就可以和後臺進行聯調測試了。


如果你覺得本文對你有幫助,麻煩動動手指頂一下,算是對本文的一個認可,如果文中有什麼錯誤的地方,還望指正,轉載請註明轉自喻志強的博客 ,謝謝!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章