Retrofit 在拦截器中加密url 并修改body 参数key-value
从一个蛋疼的需求说起:
URI加密:jjj/ 后面的URI采用AES-CBC-pkcs5padding加密后再base64编码,
然后jjj/ 换成xxxx/v2/,
例: 原始URI:jjj/sms/login, 加密内容为sms/login,加密后的URI为xxx/v2/89HlYe0vil/lOl0hgFiK0Q==
参数混淆: 在原来参数前面加上随机字符串,用3个下划线___连接。
例:原始参数{"mobile":"123456","companyId":"123123","appId":"12313231"},
混淆后 {"abc___mobile":"123456","defg___companyId":"123123","ssss___appId":"12313231"}
首先url 固定段加密:
val request = chain.request()
val builder: Request.Builder = request.newBuilder()
// 处理url 加密
val oldHttpUrl = request.url()
val oldUrl = oldHttpUrl.url().toString();
val baseUrl = Urls.formateUrl(oldUrl)
val newBaseUrl = HttpUrl.parse(baseUrl)
//设置新的url
builder.url(newBaseUrl).build()
参数获取并修改:
要区分表单提交,只适合Post请求使用!
if (request.body() is FormBody) {
val bodyBuilder = FormBody.Builder()
val formBody = request.body() as FormBody?
for (index in 0..formBody!!.size()) {
bodyBuilder.addEncoded(
Urls.getRandomString(3) + "___" + formBody.encodedName(index),
formBody.encodedValue(index)
)
}
builder.method(request.method(), bodyBuilder.build()).build()
} else {
// 参数处理
val json = LogInterceptor.parseParams(request);//获取body 参数
val infoMap: Map<*, *> =
Gson().fromJson(json, object : TypeToken<Map<String?, String?>?>() {}.type)//转为map
val requestMap = mutableMapOf<String?, Any?>()
for ((key, value) in infoMap) { //遍历map 修改key
requestMap[Urls.getRandomString(3) + "___" + key] = value
}
val newRequestBody =
RequestBody.create(request.body()!!.contentType(), Gson().toJson(requestMap));
builder.method(request.method(), newRequestBody).build()//设置新生成的RequestBody
}
完整代码:
class MHeadInterceptor : Interceptor {
@Throws(IOException::class)
override fun intercept(chain: Interceptor.Chain): Response {
val request = chain.request()
val builder: Request.Builder = request.newBuilder()
// 添加token
builder.addHeader("token", getToken()).build()
// 处理url 加密
val oldHttpUrl = request.url()
val oldUrl = oldHttpUrl.url().toString();
val baseUrl = Urls.formateUrl(oldUrl)
val newBaseUrl = HttpUrl.parse(baseUrl)
builder.url(newBaseUrl).build()
if (request.body() is FormBody) {
val bodyBuilder = FormBody.Builder()
val formBody = request.body() as FormBody?
for (index in 0..formBody!!.size()) {
bodyBuilder.addEncoded(
Urls.getRandomString(3) + "___" + formBody.encodedName(index),
formBody.encodedValue(index)
)
}
builder.method(request.method(), bodyBuilder.build()).build()
} else {
// 参数处理
val json = LogInterceptor.parseParams(request);
val infoMap: Map<*, *> =
Gson().fromJson(json, object : TypeToken<Map<String?, String?>?>() {}.type)
val requestMap = mutableMapOf<String?, Any?>()
for ((key, value) in infoMap) {
requestMap[Urls.getRandomString(3) + "___" + key] = value
}
val newRequestBody =
RequestBody.create(request.body()!!.contentType(), Gson().toJson(requestMap));
builder.method(request.method(), newRequestBody).build()
}
return chain.proceed(builder.build())
}
}
urls:
object Urls {
fun formateUrl(url: String): String {
val contentUrl = url.substring(BASE_URL.length)
return BASE_URL + "xxx/v2/" + AESUtils.aesEncrypt(contentUrl)
}
fun getRandomString(length: Int): String? {
val str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
val random = Random
val sb = StringBuffer()
for (i in 0 until length) {
val number: Int = random.nextInt(62)
sb.append(str[number])
}
return sb.toString()
}
}
parseParams方法:
companion object {
/**
* 解析请求服务器的请求参数
*
* @param request [Request]
* @return 解析后的请求信息
* @throws UnsupportedEncodingException
*/
@Throws(UnsupportedEncodingException::class)
fun parseParams(request: Request): String {
return try {
val body = request.newBuilder().build().body() ?: return ""
val requestbuffer = Buffer()
body.writeTo(requestbuffer)
var charset = Charset.forName("UTF-8")
val contentType = body.contentType()
if (contentType != null) {
charset = contentType.charset(charset)
}
var json = requestbuffer.readString(charset)
if (hasUrlEncoded(json!!)) {
json = URLDecoder.decode(
json,
convertCharset(charset)
)
}
jsonFormat(json!!)
} catch (e: IOException) {
e.printStackTrace()
"{\"error\": \"" + e.message + "\"}"
}
}
/**
* 是否可以解析
*
* @param mediaType [MediaType]
* @return `true` 为可以解析
*/
fun isParseable(mediaType: MediaType?): Boolean {
return if (mediaType?.type() == null) {
false
} else isText(mediaType) || isPlain(
mediaType
)
|| isJson(mediaType) || isForm(
mediaType
)
|| isHtml(mediaType) || isXml(
mediaType
)
}
fun isText(mediaType: MediaType?): Boolean {
return if (mediaType?.type() == null) {
false
} else "text" == mediaType.type()
}
fun isPlain(mediaType: MediaType?): Boolean {
return if (mediaType?.subtype() == null) {
false
} else mediaType.subtype()
.toLowerCase().contains("plain")
}
@JvmStatic
fun isJson(mediaType: MediaType?): Boolean {
return if (mediaType?.subtype() == null) {
false
} else mediaType.subtype().toLowerCase(Locale.getDefault()).contains("json")
}
@JvmStatic
fun isXml(mediaType: MediaType?): Boolean {
return if (mediaType?.subtype() == null) {
false
} else mediaType.subtype().toLowerCase(Locale.getDefault()).contains("xml")
}
fun isHtml(mediaType: MediaType?): Boolean {
return if (mediaType?.subtype() == null) {
false
} else mediaType.subtype().toLowerCase(Locale.getDefault()).contains("html")
}
fun isForm(mediaType: MediaType?): Boolean {
return if (mediaType?.subtype() == null) {
false
} else mediaType.subtype().toLowerCase(Locale.getDefault())
.contains("x-www-form-urlencoded")
}
fun convertCharset(charset: Charset?): String {
val s = charset.toString()
val i = s.indexOf("[")
return if (i == -1) {
s
} else s.substring(i + 1, s.length - 1)
}
}
##AES加密
public static String aesEncrypt(String content) {
try {
IvParameterSpec zeroIv = new IvParameterSpec(VIPARA.getBytes());
SecretKeySpec key = new SecretKeySpec(password.getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, key, zeroIv);
byte[] encryptedData = cipher.doFinal(content.getBytes(bm));
return new BASE64Encoder().encode(encryptedData);
//return byte2HexStr(encryptedData);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (InvalidAlgorithmParameterException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
替换key可直接使用!