0


使用Postman和JMeter进行signature签名

一、前言

​ 有些接口的请求会带上sign(签名)进行请求,各接口对sign的签名内容、方式可能不一样,但一般都是从接口的入参中选择部分内容组成一个字符串,然后再进行签名操作, 将结果赋值给sign; 完整规范的接口文档都会有sign的算法描述。这里通过Postman的Pre-request Script以及JMeter的BeanShell前置处理器进行接口签名的处理。(完整代码在每部分的最后)

被测系统teachSignServer:

Gitee:江苏豪之诺软件科技有限公司/KnowledgeBroadcast - Gitee.com

直接双击运行.exe文件即可(密钥文件与conf.ini需要与exe处于同一文件夹下)

其余工具:

1.bundle.js:https://github.com/joolfe/postman-util-lib/tree/master/postman

使用方式我们在后面使用到了再进行介绍

2.json.jar: https://mvnrepository.com/artifact/org.json/json

选择适合的版本

点击bundle

将下载的jar包置于jmeter的./lib/ext下并重启jmeter

被测接口信息:
接口URLMethodBody签名规则v0http://127.0.0.1:5000/api/v0/teachsignPOST{
"AppKey": "z417App",
"AppVer": "1.0.0",
"Data": "{"SPhone":"18662255783","EType":0}",
"DeviceName": "web",
"DeviceType": "web",
"Lang": "CN",
"Sign": "teachsign",
"TimeStamp": 1625456804
}appkey,timestamp,data,secret四个字段的值拼接,使用32位md5进行签名v1http://127.0.0.1:5000/api/v1/teachsignPOST{
"appid": "wxd930u",
"mch_id": 10100,
"device_info": 100,
"body": "{"EType":0}",
"DeviceType": "",
"nonce_str": "ibuaiVc",
"sign": "CD198C36632A274C49E5F2F028FA257C",
"source": null,
"ts": 1625456804
}1. 参与签名运算的参数选用入参里边value非空的参数
2. 参与签名运算的参数按照ASCII顺序排序
3. 组合方式:key=value通过&符连接
4. 最后加上盐key=secret(secret在conf.ini中配置,同理后面的私钥与公钥也可在其中进行配置)
5. 使用32位md5进行签名,sign的字母全大写v2http://127.0.0.1:5000/api/v2/teachsignPOST{
"busId": "",
"busCnl": "POS",
"requJnINo": "abceefgghkjlafksdffdsf",
"reqTxnTm": "16:30:16",
"serviceCode": "chengxusong",
"bussJnIno": "Arabic - Bahrain",
"sign": "fsdfsd",
"reqTxnDt": "20210907",
"nonceStr": "Language",
"sysCnl": "OKPOS",
"ts": 1631003416
}1. 参与签名运算的参数选用入参里边value非空的参数
2. 参与签名运算的参数按照ASCII顺序排序
3. 使用private_key签名
4. 使用SHA256withRSA进行签名

二、v0接口

1.Postman

获取请求参数并将body的参数转换为json对象

javascript

  1. var Json = JSON.parse(pm.request.body);

获取所需变量并将新的时间戳更新到json对象中

javascript

  1. var TimeStamp = Date.parse(new Date()) / 1000 - 10;
  2. Json.TimeStamp = TimeStamp;
  3. var AppKey = Json.AppKey;
  4. var Data = Json.Data;
  5. var secretKey = "a323f9b6-1f04-420e-adb9-b06ty67b0e63";

字符串拼接

javascript

  1. var str = AppKey + TimeStamp + Data + secretKey;

进行md5运算并将生成的hash序列转换为字符串

javascript

  1. var strmd5= CryptoJS.MD5(str).toString();

修改json对象中sign并将md5对象写回body中

javascript

  1. Json.Sign = strmd5;
  2. pm.request.body.raw = JSON.stringify(Json); // 将修改后的JSON转换回字符串格式写回到请求体中

完整代码:

javascript

  1. /*
  2. vo加密规则:
  3. appkey,timestamp,data,secret四个字段的值拼接,使用32位md5加密
  4. */
  5. /*
  6. * 获取请求参数
  7. */
  8. var Json = JSON.parse(pm.request.body); // 将body的参数转换为json对象
  9. /*
  10. * 获取所需变量
  11. */
  12. var TimeStamp = Date.parse(new Date()) / 1000 - 10; // 获取时间戳
  13. Json.TimeStamp = TimeStamp; // 修改JSON
  14. var AppKey = Json.AppKey;
  15. var Data = Json.Data;
  16. var secretKey = "a323f9b6-1f04-420e-adb9-b06ty67b0e63";
  17. /*
  18. * 拼接字符串并加密
  19. */
  20. var str = AppKey + TimeStamp + Data + secretKey;
  21. var strmd5= CryptoJS.MD5(str).toString(); // 调用方法进行md5运算并将生成的hash序列转换为字符串
  22. Json.Sign = strmd5; // 修改JSON
  23. pm.request.body.raw = JSON.stringify(Json); // 将修改后的JSON写回到请求体中

2.JMeter

在JMeter的时间戳可以直接使用JMeter自带函数在body中获取,当然也可以在BeanShell前置处理器中使用代码获取

/1000是因为JMeter默认生成的时间戳为13位时间戳,我们只需要10位即可。

导包(org.json为第三方jar包)

java

  1. import org.apache.commons.codec.digest.DigestUtils;
  2. import org.apache.jmeter.config.*;
  3. import org.json.*;

获取请求传入的body,将其转化为Json对象

java

  1. // 获取请求
  2. Arguments arguments = sampler.getArguments();
  3. // 获取请求中的body内容
  4. Argument arg = arguments.getArgument(0);
  5. // 获取body的value,并将其转化为JSONObject对象
  6. JSONObject dataobj = new JSONObject(arg.getValue());

获取变量并拼接

java

  1. String TimeStamp = dataobj.optString("TimeStamp");
  2. String AppKey = dataobj.optString("AppKey");
  3. String Data = dataobj.optString("Data");
  4. String secretKey = "a323f9b6-1f04-420e-adb9-b06ty67b0e63";
  5. String str = AppKey + TimeStamp + Data + secretKey;

进行md5运算

java

  1. sign = DigestUtils.md5Hex(str);

修改json对象的sign并转换为字符串写回body中

java

  1. dataobj.put("Sign", sign); // 修改Sign
  2. arg.setValue(dataobj.toString()); // 转换为字符串并歇回request-body中

完整代码:

java

  1. import org.apache.commons.codec.digest.DigestUtils;
  2. import org.apache.jmeter.config.*;
  3. import org.json.*;
  4. /*
  5. * 获取请求传入的body,将其转化为Json对象
  6. */
  7. // 获取请求
  8. Arguments arguments = sampler.getArguments();
  9. // 获取请求中的body内容
  10. Argument arg = arguments.getArgument(0);
  11. // 获取body的value,并将其转化为JSONObject对象
  12. JSONObject dataobj = new JSONObject(arg.getValue());
  13. /*
  14. * 获取变量并拼接字符串
  15. */
  16. // 获取变量
  17. String TimeStamp = dataobj.optString("TimeStamp");
  18. String AppKey = dataobj.optString("AppKey");
  19. String Data = dataobj.optString("Data");
  20. String secretKey = "a323f9b6-1f04-420e-adb9-b06ty67b0e63";
  21. // 字符串拼接
  22. String str = AppKey + TimeStamp + Data + secretKey;
  23. /*
  24. * 签名,更新body
  25. */
  26. sign = DigestUtils.md5Hex(str); // md5运算
  27. dataobj.put("Sign", sign); // 修改Sign
  28. arg.setValue(dataobj.toString()); // 转换为字符串并写回request-body中

三、v1接口

1.Postman

​ 获取请求参数并将body的参数转换为json对象

javascript

  1. var Json = JSON.parse(pm.request.body);

获取时间戳并修改json对象

javascript

  1. var ts = Date.parse(new Date()) / 1000 - 10;
  2. Json.ts = ts;

去除sign参数本身,然后去除值是空的参数

javascript

  1. var keys = [];
  2. // 循环遍历JSON
  3. for (let k in Json ){
  4. // 排除json中键位sign以及值为空的数据
  5. if (k == 'sign' || !Json[k]){
  6. continue;
  7. }
  8. keys.push(k); // 生成筛选后的key序列
  9. }

排序

javascript

  1. keys.sort();

拼接字符串

javascript

  1. let keys_str = '';
  2. for (let x of keys){
  3. keys_str += `${x}=${Json[x]}&`; // 使用模版字符串进行拼接
  4. }
  5. keys_str = keys_str + "key=a323f9b6-1f04-420e-adb9-b06ty67b0e63";

进行md5运算并将生成的hash序列转换为字母全大写字符串

javascript

  1. var strmd5= CryptoJS.MD5(keys_str).toString().toUpperCase();

修改json对象中sign并将md5对象写回body中

javascript

  1. Json.sign = strmd5;
  2. pm.request.body.raw = JSON.stringify(Json);

完整代码:

javascript

  1. /*
  2. v1加密规则:
  3. 1. 参与签名运算的参数选用入参里边value非空的参数
  4. 2. 参与签名运算的参数按照ASCII顺序排序
  5. 3. 组合方式:key=value通过&符连接
  6. 4. 最后加上key=secret
  7. 5. 使用32位md5签名,sign的字母全大写
  8. */
  9. /*
  10. * 获取请求参数
  11. */
  12. var Json = JSON.parse(pm.request.body);
  13. var ts = Date.parse(new Date()) / 1000 - 10; // 获取时间戳
  14. Json.ts = ts; // 修改json
  15. /*
  16. * 去除sign参数本身,然后去除值是空的参数
  17. */
  18. var keys = []; // 定义key序列
  19. // 循环遍历JSON
  20. for (let k in Json ){
  21. // 排除json中键位sign以及值为空的数据
  22. if (k == 'sign' || !Json[k]){
  23. continue;
  24. }
  25. keys.push(k); // 生成筛选后的key序列
  26. }
  27. /*
  28. * 对请求参数排序
  29. */
  30. keys.sort();
  31. /*
  32. * 拼接字符串
  33. */
  34. let keys_str = '';
  35. for (let x of keys){
  36. keys_str += `${x}=${Json[x]}&`; // 使用模版字符串进行拼接
  37. }
  38. keys_str = keys_str + "key=a323f9b6-1f04-420e-adb9-b06ty67b0e63";
  39. /*
  40. * 签名并更新body
  41. */
  42. var strmd5= CryptoJS.MD5(keys_str).toString().toUpperCase(); // 调用方法进行md5运算并将生成的hash序列转换为字母全大写字符串
  43. Json.sign = strmd5; // 修改Json
  44. pm.request.body.raw = JSON.stringify(Json);

2.JMeter

同样在body中使用内置函数定义时间戳ts

导包

java

  1. import org.apache.commons.codec.digest.DigestUtils;
  2. import org.apache.jmeter.config.*;
  3. import org.json.*;

获取请求传入的body,将其转化为Json对象

java

  1. // 获取请求
  2. Arguments arguments = sampler.getArguments();
  3. // 获取请求中的body内容
  4. Argument arg = arguments.getArgument(0);
  5. // 获取body的value,并将其转化为JSONObject对象
  6. JSONObject dataobj = new JSONObject(arg.getValue());

获取Json的key

java

  1. // 创建list存储body中的key值
  2. List keyArry = new ArrayList();
  3. // 生成迭代对象
  4. Iterator iterator = dataObj.keys();
  5. // 循环key,将其放入list
  6. for (String key : iterator) {
  7. if (!key.equals("sign") && !key.equals("Sign")) {
  8. keyArry.add(key);
  9. }
  10. }

对list进行排序

java

  1. Collections.sort(keyArry);

字符串拼接

java

  1. String str = "";
  2. for (String s : keyArry) {
  3. // log.error(s);
  4. String value = dataObj.optString(s);
  5. // 剔除值为空或值为null的参数
  6. if (!value.equals("") && !value.equals(null)) {
  7. str = str+s+"="+ value+"&";
  8. }
  9. }
  10. str = str + "key=a323f9b6-1f04-420e-adb9-b06ty67b0e63";

进行md5运算并转换为字母全大写

java

  1. String sign = DigestUtils.md5Hex(str).toUpperCase();

修改json对象的sign并转换为字符串写回body中

java

  1. dataobj.put("sign", sign); // 修改Sign
  2. arg.setValue(dataobj.toString()); // 转换为字符串并歇回request-body中

完整代码:

java

  1. import org.apache.commons.codec.digest.DigestUtils;
  2. import org.apache.jmeter.config.*;
  3. import org.json.*;
  4. /*
  5. * 获取请求传入的body,将其转化为Json对象
  6. */
  7. // 获取请求
  8. Arguments arguments = sampler.getArguments();
  9. // 获取请求中的body内容
  10. Argument arg = arguments.getArgument(0);
  11. // 获取body的value,并将其转化为JSONObject对象
  12. JSONObject dataObj = new JSONObject(arg.getValue());
  13. /*
  14. * 获取Json的key进行排序
  15. */
  16. // 创建list存储body中的key值
  17. List keyArry = new ArrayList();
  18. // 生成迭代对象
  19. Iterator iterator = dataObj.keys();
  20. // 循环key,将其放入list
  21. for (String key : iterator) {
  22. if (!key.equals("sign") && !key.equals("Sign")) {
  23. keyArry.add(key);
  24. }
  25. }
  26. /*
  27. * 对list进行排序
  28. */
  29. Collections.sort(keyArry);
  30. /*
  31. * 循环list中的key,读取对应的Value组成字符串
  32. */
  33. String str = "";
  34. for (String s : keyArry) {
  35. String value = dataObj.optString(s);
  36. // 剔除值为空或值为null的参数
  37. if (!value.equals("") && !value.equals(null)) {
  38. str = str+s+"="+ value+"&";
  39. }
  40. }
  41. str = str + "key=a323f9b6-1f04-420e-adb9-b06ty67b0e63";
  42. /*
  43. * 签名并更新body
  44. */
  45. String sign = DigestUtils.md5Hex(str).toUpperCase(); // 进行md5运算并转换为字母全大写
  46. dataobj.put("sign", sign); // 修改Sign
  47. arg.setValue(dataobj.toString()); // 转换为字符串并写回request-body中

四、v2接口

1.Postman

将下载后的json导入到postman,进入Lib install请求

发送请求,该请求会将bundle.js写入到全局变量中

获取请求参数并将body的参数转换为json对象

javascript

  1. var Json = JSON.parse(pm.request.body);

获取时间戳并修改json对象

javascript

  1. var ts = Date.parse(new Date()) / 1000 - 10;
  2. Json.ts = ts;

去除sign参数本身,然后去除值是空的参数

javascript

  1. var keys = [];
  2. // 循环遍历JSON
  3. for (let k in Json ){
  4. // 排除json中键位sign以及值为空的数据
  5. if (k == 'sign' || !Json[k]){
  6. continue;
  7. }
  8. keys.push(k); // 生成筛选后的key序列
  9. }

排序

javascript

  1. keys.sort();

拼接字符串

javascript

  1. let keys_str = '';
  2. for (let x of keys){
  3. keys_str += `${x}=${Json[x]}&`; // 使用模版字符串进行拼接
  4. }
  5. keys_str = keys_str.slice(0,-1); // 删除最后一个&

导入刚才写入到全局变量的js

javascript

  1. eval(pm.globals.get("pmlib_code"));

由于私钥过长,所以这里把私钥的内容写到环境变量中,私钥内容可在pkcs8_rsa_private_key.pem查看(私钥与公钥可自行更换,在conf.ini中进行配置即可)

获取私钥

javascript

  1. const privatekey = pm.environment.get("privatekey");

加密

javascript

  1. const sha256withrsa = new pmlib.rs.KJUR.crypto.Signature({"alg": "SHA256withRSA"}); // 生成签名对象并制定为SHA256withRSA类型
  2. sha256withrsa.init(privatekey); // 初始化privatekey
  3. sha256withrsa.updateString(keys_str); // 更新要签名的数据
  4. const sign = pmlib.rs.hextob64(sha256withrsa.sign()); // 签名并转换为Base64字符串

修改json对象中sign并将md5对象写回body中

javascript

  1. Json.sign = sign;
  2. pm.request.body.raw = JSON.stringify(Json); // 将修改后的JSON转换回字符串格式写回到请求体中

完整代码:

javascript

  1. /*
  2. v2加密规则:
  3. 1. 参与签名运算的参数选用入参里边value非空的参数
  4. 2. 参与签名运算的参数按照ASCII顺序排序
  5. 3. 使用private_key签名
  6. 4. 使用SHA256withRSA进行签名
  7. */
  8. /*
  9. * 获取请求参数
  10. */
  11. var Json = JSON.parse(pm.request.body);
  12. var ts = Date.parse(new Date()) / 1000 - 10; // 获取时间戳
  13. Json.ts = ts; // 修改json
  14. /*
  15. * 去除sign参数本身,然后去除值是空的参数
  16. */
  17. var keys = []; // 定义key序列
  18. // 循环遍历JSON
  19. for (let k in Json ){
  20. // 排除json中键位sign以及值为空的数据
  21. if (k == 'sign' || !Json[k]){
  22. continue;
  23. }
  24. keys.push(k); // 生成筛选后的key序列
  25. }
  26. /*
  27. * 对请求参数排序
  28. */
  29. keys.sort();
  30. /*
  31. * 拼接字符串
  32. */
  33. let keys_str = '';
  34. for (let x of keys){
  35. keys_str += `${x}=${Json[x]}&`; // 使用模版字符串进行拼接
  36. }
  37. keys_str = keys_str.slice(0,-1); // 删除最后一个&
  38. /*
  39. * 加密并更新body
  40. */
  41. eval(pm.globals.get("pmlib_code")); // 导入写入到全局变量的js
  42. const privatekey = pm.environment.get("privatekey"); // 从环境变量获取私钥
  43. const sha256withrsa = new pmlib.rs.KJUR.crypto.Signature({"alg": "SHA256withRSA"}); // 生成签名对象并制定为SHA256withRSA类型
  44. sha256withrsa.init(privatekey); // 初始化privatekey
  45. sha256withrsa.updateString(keys_str); // 更新要签名的数据
  46. const sign = pmlib.rs.hextob64(sha256withrsa.sign()); // 签名并转换为Base64字符串
  47. Json.sign = sign;
  48. pm.request.body.raw = JSON.stringify(Json);

2.JMeter

同样在body中使用内置函数定义时间戳ts,同时添加用户定义的变量配置元件来存放私钥

导包

java

  1. import org.apache.jmeter.config.*;
  2. import org.apache.commons.codec.digest.DigestUtils;
  3. import org.json.*;
  4. import java.security.*;
  5. import java.security.spec.PKCS8EncodedKeySpec;

获取请求传入的body,将其转化为Json对象

java

  1. // 获取请求
  2. Arguments arguments = sampler.getArguments();
  3. // 获取请求中的body内容
  4. Argument arg = arguments.getArgument(0);
  5. // 获取body的value,并将其转化为JSONObject对象
  6. JSONObject dataobj = new JSONObject(arg.getValue());

获取Json的key

java

  1. // 创建list存储body中的key值
  2. List keyArry = new ArrayList();
  3. // 生成迭代对象
  4. Iterator iterator = dataObj.keys();
  5. // 循环key,将其放入list
  6. for (String key : iterator) {
  7. if (!key.equals("sign") && !key.equals("Sign")) {
  8. keyArry.add(key);
  9. }
  10. }

对list进行排序

java

  1. Collections.sort(keyArry);

字符串拼接

java

  1. String str = "";
  2. for (String s : keyArry) {
  3. // log.error(s);
  4. String value = dataObj.optString(s);
  5. // 剔除值为空或值为null的参数
  6. if (!value.equals("") && !value.equals(null)) {
  7. str = str+s+"="+ value+"&";
  8. }
  9. }
  10. //删除最后一个&
  11. str = str.substring(0,str.length()-1);

读取私钥

​ java中读取私钥需要删除前面的“-----BEGIN PRIVATE KEY-----”和后面的“-----END PRIVATE KEY-----”,且需要key首尾连接中间无换行或空格。

java

  1. String privateKeyString = vars.get("privateKey"); // 从用户定义的变量中读取私钥
  2. privateKeyString = privateKeyString.replace(" ", ""); // 删除多余的空格
  3. byte[] privateKeyBytes = Base64.getDecoder().decode(privateKeyString); // 将Base64解码转化为字符串
  4. PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes); // 根据给定的编码密钥创建一个新的 PKCS8EncodedKeySpec
  5. PrivateKey privateKey = KeyFactory.getInstance("RSA").generatePrivate(keySpec); // 生成RSA的私钥对象。

创建 Signature 对象并初始化

java

  1. Signature signature = Signature.getInstance("SHA256withRSA"); // 生成SHA256withRSA的Signature 对象
  2. signature.initSign(privateKey); // // 初始化签署签名的私钥

更新要签名的数据

java

  1. signature.update(str.getBytes("UTF-8")); // 更新要签名或验证的字节

签名

java

  1. byte[] signatureBytes = signature.sign(); // 执行签名
  2. String sign = Base64.getEncoder().encodeToString(signatureBytes); // 将签名结果转换为 Base64 字符串

修改json对象的sign并转换为字符串写回body中

java

  1. dataobj.put("sign", sign); // 修改Sign
  2. arg.setValue(dataobj.toString()); // 转换为字符串并歇回request-body中

完整代码:

java

  1. import org.apache.jmeter.config.*;
  2. import org.apache.commons.codec.digest.DigestUtils;
  3. import org.json.*;
  4. import java.security.*;
  5. import java.security.spec.PKCS8EncodedKeySpec;
  6. /*
  7. * 获取请求传入的body,将其转化为Json对象
  8. */
  9. // 获取请求
  10. Arguments arguments = sampler.getArguments();
  11. // 获取请求中的body内容
  12. Argument arg = arguments.getArgument(0);
  13. // 获取body的value,并将其转化为JSONObject对象
  14. JSONObject dataObj = new JSONObject(arg.getValue());
  15. /*
  16. * 获取Json的key进行排序
  17. */
  18. // 创建list存储body中的key值
  19. List keyArry = new ArrayList();
  20. // 生成迭代对象
  21. Iterator iterator = dataObj.keys();
  22. // 循环key,将其放入list
  23. for (String key : iterator) {
  24. if (!key.equals("sign") && !key.equals("Sign")) {
  25. keyArry.add(key);
  26. // log.error(key);
  27. }
  28. }
  29. // 对list进行排序
  30. Collections.sort(keyArry);
  31. /*
  32. * 循环list中的key,读取对应的Value组成字符串
  33. */
  34. String str = "";
  35. for (String s : keyArry) {
  36. // log.error(s);
  37. String value = dataObj.optString(s);
  38. if (!value.equals("")) {
  39. str = str+s+"="+ value+"&";
  40. }
  41. }
  42. //删除最后一个&
  43. str = str.substring(0,str.length()-1);
  44. /*
  45. * 读取私钥
  46. */
  47. String privateKeyString = vars.get("privateKey"); // 从用户定义的变量中读取私钥
  48. privateKeyString = privateKeyString.replace(" ", ""); // 删除多余的空格
  49. byte[] privateKeyBytes = Base64.getDecoder().decode(privateKeyString); // 将Base64解码转化为字符串
  50. PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes); // 根据给定的编码密钥创建一个新的 PKCS8EncodedKeySpec
  51. PrivateKey privateKey = KeyFactory.getInstance("RSA").generatePrivate(keySpec); // 生成RSA的私钥对象。
  52. /*
  53. * 读创建 Signature 对象并初始化
  54. */
  55. Signature signature = Signature.getInstance("SHA256withRSA"); // 生成SHA256withRSA的Signature 对象
  56. signature.initSign(privateKey); // 初始化签署签名的私钥
  57. //
  58. /*
  59. * 更新要签名的数据化
  60. */
  61. signature.update(str.getBytes("UTF-8")); // 更新要签名或验证的字节
  62. /*
  63. * 签名并更新body
  64. */
  65. byte[] signatureBytes = signature.sign(); // 签署所有更新字节的签名
  66. // 将签名结果转换为 Base64 字符串
  67. String sign = Base64.getEncoder().encodeToString(signatureBytes); // 编码为Base64字符串
  68. dataobj.put("sign", sign); // 修改Sign
  69. arg.setValue(dataobj.toString()); // 转换为字符串并歇回request-body中
  70. ​​​​​

​​​​​​​​​​​​​​

标签: lua 开发语言

本文转载自: https://blog.csdn.net/jj2772367224/article/details/136262451
版权归原作者 鱼鱼说测试 所有, 如有侵权,请联系我们删除。

“使用Postman和JMeter进行signature签名”的评论:

还没有评论