JMeter BeanShell 实现接口签名验签及加解密

在利用JMeter进行接口测试或者性能测试的时候,我们需要处理一些复杂的请求,比如对接口请求参数进行签名,加密,响应数据的验签及解密,以及接口公共参数的处理,此时就需要利用BeanShell脚本了,关于BeanShell的使用小伙伴们可以查看网上相关文章。今天主要和大家分享下接口签名,验签,加解密,以及处理公共参数的例子,希望能帮助到小伙伴们。

一,思路

  • 约定:约定接口有统一的请求及响应格式,如:

    请求协议公共部分

参数类型是否必选描述
appKeyString应用key
nonceString32位UUID随机字串,格式如:296f6fdd570244d98b6046ec135a5b8a
signString签名
timestampLong请求时间戳,
transactionSnString交易流水号
parameterObject请求的业务对象

响应协议公共部分

参数类型描述
codeString返回码
messageString返回消息,如错误信息
timestampString响应时间
transactionSnString交易流水号
signString签名
dataObject返回的业务对象

基于此约定,我们才能进一步统一处理。

  • 引入外部签名及加解密工具包

  • JMeter的HTTP请求->请求参数中只填写业务对象(parameter)

  • 利用前置处理器(BeanShell PreProcessor),组装公共请求对象->对业务参数对象进行加密->签名

  • 利用后置处理器(BeanShell PostProcessor)对响应报文进行验签->解密。

二,实现

整体效果如下图:

微信图片编辑_20210518115705.jpg

关于如何建立测试计划,线程组就不用一一描述了,这里只关注核心功能实现。

  • HTTP请求参数(parameter)部分,如:

{
    "idCardNo":"511622198312241918",
    "name":"Leo"}

  • 接口调用前置处理器-签名/加密(BeanShell PreProcessor),BeanShell代码如下:

  • //引入依赖import com.javacoo.service.base.security.util.SignUtil;import com.javacoo.service.base.security.util.SecurityUtil;import com.javacoo.service.base.utils.WebUtil;import com.javacoo.service.base.utils.FastJsonUtil;import com.javacoo.service.base.BaseRequest;import java.util.Calendar;import java.util.Map;import org.apache.jmeter.config.Arguments; //开始处理log.info("接口调用前置处理器-签名/加密相关处理");Arguments args = sampler.getArguments(); //获取请求参数String body = args.getArgument(0).getValue();log.info("业务参数:{}",body);//获取签名所需参数String appKey = "${appKey}";String secretkey = "${secretkey}";String nonce = WebUtil.genTransSn();String transactionSn = WebUtil.genTransSn();Long timestamp = Calendar.getInstance().getTimeInMillis();//加密Map bodyMap = FastJsonUtil.stringToCollect(body);log.info("params:{}",bodyMap);for(Map.Entry entry : bodyMap.entrySet()){
        entry.setValue(SecurityUtil.encryptDes(entry.getValue(),secretkey));}body = FastJsonUtil.toJSONString(bodyMap);log.info("加密后业务参数:{}",body);//签名String sign = SignUtil.clientSign(body,nonce,timestamp.toString(),secretkey);log.info("sign:{}",sign);//组装接口请求对象BaseRequest baseRequest = new BaseRequest();baseRequest.setAppKey(appKey);baseRequest.setNonce(nonce);baseRequest.setTimestamp(timestamp);baseRequest.setTransactionSn(transactionSn);baseRequest.setSign(sign);baseRequest.setParameter(FastJsonUtil.toBean(body));//转换为JSON字符串String reqBody = FastJsonUtil.toJSONString(baseRequest);log.info("reqBody:{}",reqBody);//重置参数值args.getArgument(0).setValue(reqBody);

    • 接口调用后置处理程序-验证签名/解密(BeanShell PostProcessor),BeanShell代码如下:

    //引入依赖import com.javacoo.service.base.security.util.SignUtil;import com.javacoo.service.base.BaseResponse;import com.javacoo.service.base.utils.FastJsonUtil;import org.apache.commons.lang3.StringUtils;//开始处理log.info("接口调用后置处理器-验证签名");String responseData = prev.getResponseDataAsString();log.info("返回数据:{}",responseData);BaseResponse baseResponse = FastJsonUtil.toBean(responseData, BaseResponse.class);if(StringUtils.isBlank(baseResponse.getSign()) || baseResponse.getData().get() == null){
        return;}//转换String s = FastJsonUtil.toJSONString(baseResponse.getData().get());log.info("请求返回业务json:{}",s);log.info("请求返回签名:{}",baseResponse.getSign());String secretkey = "${secretkey}";//验证签名if (SignUtil.cloudVerifySign(baseResponse.getSign(), s,baseResponse.getTransactionSn(),baseResponse.getTimestamp().toString(), secretkey)) {
           log.info("返回数据合法");} else {
           log.info("返回数据被篡改");}//解密,TODO

    三,注意事项及问题

    • JMeter不支持java1.5以后的语法,不支持泛型,如要使用则需要封装成JAR包。