Android结合Retrofit实现统一加解密处理(Get、Post、Delete、Put)

Android中对接口进行统一加密

在之前的博客中我们介绍了 加密方案的选择Android中加解密需要注意的地方

本篇博客我们主要来看一下Android结合Retrofit进行加解密时的注意事项。

在开发过程中,接口是很多的,我们不可能分别对每个接口的请求数据都进行加密,这样写起来以及后期维护是非常麻烦的,所以,肯定要是统一处理的
还有我们常用的GetPostDeletePut请求他们的请求数据存放位置是不一样的,所以,我们需要对不同的请求方式做处理。
上传文件时,一般是不需要加密的,还有通过Retrofit请求第三方接口时也是不需要加密的,这些我们都需要考虑到。

目前来讲,我们最常使用的网络请求框架就是Retrofit了,Retrofit实际上就是对OkHttp的封装,网上的一些博客对加解密的处理是在转换器中处理的,实际上我认为这种方式并不好,首先我们来看一下GsonConverterFactory的源码.
Android结合Retrofit实现统一加解密处理(Get、Post、Delete、Put)_第1张图片
看过源码你会发现,转换器只能对响应体和请求体进行处理,解密的时候还好说,加密的时候如果你使用的是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()

然后就可以和后台进行联调测试了。


如果你觉得本文对你有帮助,麻烦动动手指顶一下,算是对本文的一个认可,如果文中有什么错误的地方,还望指正,转载请注明转自喻志强的博客 ,谢谢!

你可能感兴趣的:(Android,网络安全)