Android中對接口進行統一加密
在之前的博客中我們介紹了 加密方案的選擇 和 Android中加解密需要注意的地方
本篇博客我們主要來看一下Android結合Retrofit進行加解密時的注意事項。
在開發過程中,接口是很多的,我們不可能分別對每個接口的請求數據都進行加密,這樣寫起來以及後期維護是非常麻煩的,所以,肯定要是統一處理的
還有我們常用的Get、Post、Delete、Put請求他們的請求數據存放位置是不一樣的,所以,我們需要對不同的請求方式做處理。
上傳文件時,一般是不需要加密的,還有通過Retrofit請求第三方接口時也是不需要加密的,這些我們都需要考慮到。
目前來講,我們最常使用的網絡請求框架就是Retrofit了,Retrofit實際上就是對OkHttp的封裝,網上的一些博客對加解密的處理是在轉換器中處理的,實際上我認爲這種方式並不好,首先我們來看一下GsonConverterFactory的源碼.
看過源碼你會發現,轉換器只能對響應體和請求體進行處理,解密的時候還好說,加密的時候如果你使用的是Get或者Delete這中請求方式時,轉換器是不好進行處理的。所以,關於Retrofit的統一加解密還是建議在攔截器中進行處理。
下面我們來總結一下注意事項:
- 加解密要統一進行處理,方便維護
- 加密時要對不同的加密方式進行不同的加密處理
- 第三方接口,不加密
- 上傳時不加密
Retrofit 統一加密攔截器
攔截器對請求數據加密流程
- 獲取請求的數據
- 對請求數據進行加密
- 根據不同的請求方式構造新的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()
然後就可以和後臺進行聯調測試了。
如果你覺得本文對你有幫助,麻煩動動手指頂一下,算是對本文的一個認可,如果文中有什麼錯誤的地方,還望指正,轉載請註明轉自喻志強的博客 ,謝謝!