Retrofit 在拦截器中加密url 并修改body 参数key-value

本文介绍了如何使用Retrofit在拦截器中实现URI采用AES-CBC-pkcs5padding加密和参数的随机混淆,包括URL固定段加密、表单参数处理和Post请求的适配。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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;
    }

AES加密工具类

替换key可直接使用!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值