在利用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)对响应报文进行验签->解密。
二,实现
整体效果如下图:
关于如何建立测试计划,线程组就不用一一描述了,这里只关注核心功能实现。
-
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包。
一些信息
路漫漫其修远兮,吾将上下而求索
码云:https://gitee.com/javacoo
QQ群:164863067
作者/微信:javacoo
邮箱:xihuady@126.com