使用注解为部分接口添加加密逻辑

使用了 HTTPS 的网络请求, 其中 JSON 数据有必要做额外的加密吗?
个人疑惑,故在v2ex提了这个问题,大家讨论挺热闹的。

另外,根据一个网友的评论,收获一篇好文.HTTPS实战之单向验证和双向验证

##问题描述及解决

需要对部分接口中的JSON数据加密,由于仅是部分接口需要处理,故想到用注解来标记需要加密的接口。

1
2
3
4
5
6
// 服务器返回的基础类
data class BaseModel<Data>(
val code: Int,
val msg: String?,
val data: Data? //
)

Data是个泛型,不同接口对应着不同类型,在没有加密逻辑时,该JSON数据中data就是相应的JSON对象。

添加加密逻辑后,data成了加密过后的密文,类型是String, 故想要反序列出我们想要的Data对象,我们需要多一个额外操作, 先将该密文解密成相应的json,后续使用Gson反序列既可。

具体步骤
1,标记需要加密的接口

1
2
3
4
5
6
7

@POST("public/login")
@EncryptStatic //使用该注解来标记该接口加密
fun test_login(@Body requestBody: RequestBody):Observable<BaseModel<LoginResult>>


// 返回一个Converter,用于将JSON数据转换成我们想要的对象

2,获取接口方法中的注解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
int encrypt = 0; // 用该变量标记加密类型,0,则无加密,1则需机密
if (annotations.length > 0) {
for (Annotation annotation : annotations) {
//查找注解集合中是否存在加密注解
if (annotation.annotationType() == EncryptStatic.class) {
encrypt = 1;
break;
} else if (annotation.annotationType() == EncryptDynamic.class) {
encrypt=2;
break;
}
}
}
return new CustomizeGsonResponseBodyConverter<>(gson, adapter,encrypt);
}

3,为对应的注解添加我们的额外操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

@Override
public T convert(ResponseBody value) throws IOException {
//把responsebody转为string
String response = value.string();
BaseModel baseResponse = gson.fromJson(response, BaseModel.class);
if (encryptType == 1) {
// 将密文解密成对应的Json字符串
String dataStr = EncryptExtKt.aesDecrypt(Objects.requireNonNull(baseResponse.getData().toString()), "});
// 以下3行实际是拼凑json字符串
T data=gson.fromJson(dataStr, new TypeToken<T>(){}.getType());
baseResponse = new BaseModel(baseResponse.getCode(), baseResponse.getMsg(), data);
response = gson.toJson(baseResponse, BaseModel.class);
}
try {
// 将json数据反序列化了哈
return adapter.fromJson(response);
} finally {
value.close();
}
}

##总结

大概就是这个流程,在json和对象转换之间插入加解密,第一份工作的项目写过这个逻辑,现在不过是加了一个注解。另外,回头看了第一个项目时,发觉自己 代码规范居然变糟糕了~