在利用JMeter进行接口测试或者性能测试的时候,我们需要处理一些复杂的请求,比如对接口请求参数进行签名,加密,响应数据的验签及解密,以及接口公共参数的处理,此时就需要利用BeanShell脚本了,关于BeanShell的使用小伙伴们可以查看网上相关文章。今天主要和大家分享下接口签名,验签,加解密,以及处理公共参数的例子,希望能帮助到小伙伴们。
约定:约定接口有统一的请求及响应格式,如:
请求协议公共部分
参数 | 类型 | 是否必选 | 描述 |
---|---|---|---|
appKey | String | 是 | 应用key |
nonce | String | 是 | 32位UUID随机字串,格式如:296f6fdd570244d98b6046ec135a5b8a |
sign | String | 是 | 签名 |
timestamp | Long | 是 | 请求时间戳, |
transactionSn | String | 是 | 交易流水号 |
parameter | Object | 否 | 请求的业务对象 |
响应协议公共部分
参数 | 类型 | 描述 |
---|---|---|
code | String | 返回码 |
message | String | 返回消息,如错误信息 |
timestamp | String | 响应时间 |
transactionSn | String | 交易流水号 |
sign | String | 签名 |
data | Object | 返回的业务对象 |
基于此约定,我们才能进一步统一处理。
引入外部签名及加解密工具包
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包。
2023-12-13T11:46:19
2023-12-13T11:48:22
2024-01-02T09:07:42
2024-01-02T09:07:20
2024-01-02T09:06:50
2024-01-02T09:06:26
2024-01-02T09:06:01
2024-01-02T09:05:20
2024-01-02T09:04:49
2024-01-02T09:04:17