天天看点

Jmeter测试-用Beanshell进行MD5加密后生成sign前言

前言

部分公司为了提高接口请求的安全性,避免被抓包后乱请求,对外的接口都会用到sign签名,对不同的客户提供不同的secretKey 。用 jmeter 测试带有签名的接口,需要发起请求之前把body里面的sign参数的值修改为签名的值。

sign签名规则

签名参数sign生成的方法

  • 第1步: 将所有参数,除去sign本身,以及值是空的参数,将参数名ASCII从小到大排序(字典序)
  • 第2步: 然后把排序后的参数,以及参数对应的参数值,使用 URL 键值对的格式(即 key1=value1&key2=value2…)拼接成字符串
  • 第3步: 在第2步得到的字符串最后拼接上 key 得到新的字符串,并进行 MD5 运算,得到32位字符串,最后把字符串小写转成大写,得到的字符串作为sign的值

假设接口的请求方式为post,接口的请求参数如下,提供给客户的secretKey =aaaabbbb:

body = {
    "username": "test",
    "pwd": "123456",
    "phone": "",
    "sign": "签名后的值"
}
           

其中sign参数对应的sign_value就是签名的值。

jmeter生成签名发送请求步骤如下

先右键线程组->取样器->添加HTTP请求,填写请求方式,请求参数等,请求参数中的变量使用${ }格式

Jmeter测试-用Beanshell进行MD5加密后生成sign前言

右键线程组->配置原件->添加HTTP信息头管理器,填写HTTP信息头信息

Jmeter测试-用Beanshell进行MD5加密后生成sign前言

右键线程组->配置原件->用户定义的变量,添加请求参数中的变量

Jmeter测试-用Beanshell进行MD5加密后生成sign前言

右键线程组->前置处理器->添加BeanShell 预处理程序,编写前置验签脚本

Jmeter测试-用Beanshell进行MD5加密后生成sign前言

完整代码实现如下:

import org.apache.jmeter.config.Arguments;
import org.apache.jmeter.config.Argument;
import org.apache.commons.codec.digest.DigestUtils; 
import java.io.*;
import org.json.*;
 
/*
 * 获取请求传入的body,将其转化为Json对象
 */
// 获取请求
Arguments arguments = sampler.getArguments();
// 获取请求中的body内容
Argument arg = arguments.getArgument(0);
// 获取body的value,并将其转化为JSONObject对象
JSONObject dataObj = new JSONObject(arg.getValue()); 
log.info("---------------"+dataObj);

 
/*
 * 获取Json的key进行排序
 */
// 创建list存储body中的key值
List keyArry = new ArrayList();
// 生成迭代对象
Iterator iterator = dataObj.keys(); 
// 循环key,将其放入list
while (iterator.hasNext()) {
	String key = (String) iterator.next();
	// 去除sign
	if (!key.equals("sign") && !key.equals("Sign")) {
		keyArry.add(key);
		}
	}
// 对list进行排序
Collections.sort(keyArry);
 
// 循环list中的key,读取对应的Value组成字符串
String reStr = "";
for (String s : keyArry) {
	String value = dataObj.getString(s);
	if (!value.equals("")) {
		reStr = reStr+s+"="+ value+"&";
		}
	}
//删除最后一个&
reStr = reStr.substring(0,reStr.length()-1);
log.info("***删除后最后一个&后的字符串***"+reStr);
/*
 * 根据reStr+secretKey生成sign,并放入原有的body,传入请求
 */
String secretKey = "aaaabbbb";
String md5_before = reStr+"&key="+secretKey;
log.info("#######加密前#####"+md5_before);
String md5_after = DigestUtils.md5Hex(md5_before).toUpperCase();
log.info("#############"+md5_after);

// 将sign放入json对象
dataObj.put("sign", md5_after);
// 将json转换为可以发送的内容
String postData = dataObj.toString();
// 替换请求中的发送内容
arg.setValue(postData);
 
log.info("***新请求数据*****"+postData);
 
           

右键线程组->监听器->察看结果树,发送请求就可以看到响应结果(ps:这里用的不是真实接口,所以请求不成功,真实接口是可以成功的)

Jmeter测试-用Beanshell进行MD5加密后生成sign前言

踩过的坑!!!

在对参数进行加密得到签名sign后,一开始的想法是直接通过vars.put(“sign”,md5_after)把值赋给变量,然后请求中可以直接使用变量{{sign}},但是试了很多次后一直未生效,请求中的sign没有替换成功

原因:在用Arguments args = sampler.getArguments()去获取参数时,实际上请求参数已经执行过变量替换操作了,所以此时在beanshell前置处理器中再使用vars.put去修改变量的值是不生效的

解决办法:通过Argument 的setValue方法去修改参数值,直接替换加密前的请求内容