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()
然后就可以和后台进行联调测试了。
如果你觉得本文对你有帮助,麻烦动动手指顶一下,算是对本文的一个认可,如果文中有什么错误的地方,还望指正,转载请注明转自喻志强的博客 ,谢谢!