android 网络拦截器统一处理请求参数和返回值加解密实现

前言

项目中遇到参数加密和返回结果加密的业务

这里写一下实现 一来加深记忆 二来为以后参考铺垫

需求

项目在开发中涉及到 登陆 发验证码 认证 等前期准备接口

这些接口需要单独处理 比如不加密 或者有其他的业务需求

剩下的是登陆成功以后的业务需求接口 针对入参和返回值做了RSA AES加密

需求大概是这样 下面看下代码实现逻辑

实现

在网络框架的配置类里添加加密拦截器

java 复制代码
 HttpsUtils.SSLParams sslParams = HttpsUtils.getSslSocketFactory();
        OkHttpClient.Builder mOkHttpBuilder = new OkHttpClient.Builder()
                .connectTimeout(CONN_TIME_OUT, TimeUnit.SECONDS)
                .readTimeout(READ_TIME_OUT, TimeUnit.SECONDS)
                .writeTimeout(WRITE_TIME_OUT, TimeUnit.SECONDS)
                .sslSocketFactory(sslParams.sSLSocketFactory, sslParams.trustManager)
                .addInterceptor(new EncryptionInterceptor()) //加密拦截器 统一处理

解析

我的业务场景是 前期的 登陆 发验证码 认证 接口不需要做加密

所以我需要在加密拦截器前期做单独处理

java 复制代码
 		 //认证接口不处理加密需求
        if (url.encodedPath().equals("xxx/auth")) {
            return chain.proceed(request);
        }
		
		//登陆和验证码都是get接口所以在这里统一拦截 
        if (method.equals("get") || method.equals("delete")) {
            return chain.proceed(request);
        }

处理完特殊业务场景 就剩统一的post接口 参数统一封装成body

java 复制代码
 		 //请求接口请求参数
        String param = InterceptorUtils.bodyToString(request);

        //获取加密的key
        String aesKey = Hawk.get(AppCode.AES_EKY);
        String encryptData = AESUtils.encrypt(param, aesKey);

        //拿到加密后的json字符串
        String json = new Gson().toJson(new JsonRequest(encryptData));
        RequestBody body = RequestBody.create(request.body().contentType(), json);
        request = request.newBuilder().post(body).build();
        Response response = chain.proceed(request);

下图是加密后的参入 统一用data作为加密key-valuekey用于后端解析

再来看一下返回值解密的代码实现 这里有2个点需要注意一下

对于后端返回的类型 无非是对象Object或者数组Array 2种情况 统一封装

先来看一下返回的加密格式

json 复制代码
 {
    	"code":20000,
    	"data":"N1bBAjZ4m6PGGWJmu53PzSOcyjjUL0Jo3UITcEgmxY
    	    	WcnBZSXKXRK81bS65JVoB8ouAuBLSSQvzVxHAc
    			/pRbdUentgpppoe8wfhKvLuVu9LhVPK9y6I9/rf5nNm4h0+R62ubdUNINLsi6tl+j
				/Gn/gMPAzIoEFtVyQMQvHJ1sH4uh4as0Tnxu51aEknNc8Pm",
    	"errorId":"",
    	"message":"操作成功"
    }

上图中,data是我们的业务返回数据 它可能是Array也可能是Object
encryptData 加密字符串

java 复制代码
	//说明是数组
   if (encryptData != null && encryptData.startsWith("[")) {
            JSONArray jsonArray = JSONArray.parseArray(encryptData);
            decryptObj.setData(jsonArray);
   } else if (encryptData != null && encryptData.startsWith("{")) {
               //说明是对象
            JSONObject jsonObject = JSONObject.parseObject(encryptData);
            decryptObj.setData(jsonObject);
      }

EncryptionInterceptor 实现

java 复制代码
public class EncryptionInterceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        okhttp3.HttpUrl url = request.url();
        String method = request.method().toLowerCase().trim();

        //认证接口不处理加密需求
        if (url.encodedPath().equals("/isp/app/worker/auth")) {
            return chain.proceed(request);
        }

        if (method.equals("get") || method.equals("delete")) {
            return chain.proceed(request);
        }
        //请求接口请求参数
        String param = InterceptorUtils.bodyToString(request);

        //获取加密的key
        String aesKey = Hawk.get(AppCode.AES_EKY);
        String encryptData = AESUtils.encrypt(param, aesKey);

        //拿到加密后的json字符串
        String json = new Gson().toJson(new JsonRequest(encryptData));
        RequestBody body = RequestBody.create(request.body().contentType(), json);
        request = request.newBuilder().post(body).build();
        Response response = chain.proceed(request);
        return Decrypt(response);
    }


    /**
     * 返回值解密
     * @param response 返回值
     * @return response
     */
    private Response Decrypt(Response response) {
        try {
            Response.Builder builder = response.newBuilder();
            Response clone = builder.build();

            //成功 判断是否等于200
            if (clone.code() != 200) {
                return response;
            }
            ResponseBody body = clone.body();
            if (body != null) {
                MediaType mediaType = body.contentType();
                if (mediaType != null) {
                    if (InterceptorUtils.isText(mediaType)) {
                        String aesKey = Hawk.get(AppCode.AES_EKY);
                        BaseResult result = new 
                        Gson().fromJson(body.string(),BaseResult.class);
                        String encryptData = 
                        AESUtils.decrypt(result.getData().toString(), aesKey);
                        ALog.e("解密返回数据 ->" + encryptData);

                        BaseResult decryptObj = new BaseResult();
                        decryptObj.setCode(result.getCode());
                        decryptObj.setErrorId(result.getErrorId());
                        decryptObj.setMessage(result.getMessage());
                        //说明是数组
                        if (encryptData != null && encryptData.startsWith("[")) {
                            JSONArray jsonArray = JSONArray.parseArray(encryptData);
                            decryptObj.setData(jsonArray);
                        } else if (encryptData != null && encryptData.startsWith("{")) {
                            //说明是对象
                            JSONObject jsonObject = JSONObject.parseObject(encryptData);
                            decryptObj.setData(jsonObject);
                        }
                        String strJson = new Gson().toJson(decryptObj);
                        body = ResponseBody.create(mediaType, strJson);
                        return response.newBuilder().body(body).build();
                    }
                }
            }
        } catch (Exception e) {
            ALog.e("解密错误:" + e.getMessage());
        }

        return response;
    }
}

有什么问题欢迎交流~

相关推荐
我叫张小白。20 小时前
Spring Boot拦截器详解:实现统一的JWT认证
java·spring boot·web·jwt·拦截器·interceptor
Zender Han20 小时前
Flutter 新版 Google Sign-In 插件完整解析(含示例讲解)
android·flutter·ios·web
jun_bai1 天前
python写的文件备份网盘程序
运维·服务器·网络
爱吃牛肉的大老虎1 天前
网络传输架构之gRPC讲解
网络·架构
Warren981 天前
Python自动化测试全栈面试
服务器·网络·数据库·mysql·ubuntu·面试·职场和发展
来来走走1 天前
Android开发(Kotlin) LiveData的基本了解
android·开发语言·kotlin
云飞云共享云桌面1 天前
无需配置传统电脑——智能装备工厂10个SolidWorks共享一台工作站
运维·服务器·前端·网络·算法·电脑
骆驼10241 天前
手机热点和无线路由器在 IPv6 工作模式上的区别
网络·ipv6
。puppy1 天前
MySQL 远程登录实验:通过 IP 地址跨机器连接实战指南
android·adb
dongdeaiziji1 天前
深入理解 Kotlin 中的构造方法
android·kotlin