【Postman&JMeter】使用Postman和JMeter进行signature签名
使用Postman和JMeter進行signature簽名
目錄-
使用Postman和JMeter進行signature簽名
- 一、前言
-
二、v0接口
- 1.Postman
- 2.JMeter
-
三、v1接口
- 1.Postman
- 2.JMeter
-
四、v2接口
- 1.Postman
- 2.JMeter
一、前言
? 有些接口的請求會帶上sign(簽名)進行請求,各接口對sign的簽名內容、方式可能不一樣,但一般都是從接口的入參中選擇部分內容組成一個字符串,然后再進行簽名操作, 將結果賦值給sign; 完整規范的接口文檔都會有sign的算法描述。這里通過Postman的Pre-request Script以及JMeter的BeanShell前置處理器進行接口簽名的處理。(完整代碼在每部分的最后)
被測系統teachSignServer:
Gitee:https://gitee.com/z417/knowledgebroadcast/tree/master/teachSignServer-tools
直接雙擊運行.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
被測接口信息:
| 接口 | URL | Method | Body | 簽名規則 |
|---|---|---|---|---|
| v0 | http://127.0.0.1:5000/api/v0/teachsign | POST | { "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進行簽名 |
| v1 | http://127.0.0.1:5000/api/v1/teachsign | POST | { "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的字母全大寫 |
| v2 | http://127.0.0.1:5000/api/v2/teachsign | POST | { "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對象
var Json = JSON.parse(pm.request.body);
獲取所需變量并將新的時間戳更新到json對象中
var TimeStamp = Date.parse(new Date()) / 1000 - 10;
Json.TimeStamp = TimeStamp;
var AppKey = Json.AppKey;
var Data = Json.Data;
var secretKey = "a323f9b6-1f04-420e-adb9-b06ty67b0e63";
字符串拼接
var str = AppKey + TimeStamp + Data + secretKey;
進行md5運算并將生成的hash序列轉換為字符串
var strmd5= CryptoJS.MD5(str).toString();
修改json對象中sign并將md5對象寫回body中
Json.Sign = strmd5;
pm.request.body.raw = JSON.stringify(Json); // 將修改后的JSON轉換回字符串格式寫回到請求體中
完整代碼:
/*
vo加密規則:
appkey,timestamp,data,secret四個字段的值拼接,使用32位md5加密
*/
/*
* 獲取請求參數
*/
var Json = JSON.parse(pm.request.body); // 將body的參數轉換為json對象
/*
* 獲取所需變量
*/
var TimeStamp = Date.parse(new Date()) / 1000 - 10; // 獲取時間戳
Json.TimeStamp = TimeStamp; // 修改JSON
var AppKey = Json.AppKey;
var Data = Json.Data;
var secretKey = "a323f9b6-1f04-420e-adb9-b06ty67b0e63";
/*
* 拼接字符串并加密
*/
var str = AppKey + TimeStamp + Data + secretKey;
var strmd5= CryptoJS.MD5(str).toString(); // 調用方法進行md5運算并將生成的hash序列轉換為字符串
Json.Sign = strmd5; // 修改JSON
pm.request.body.raw = JSON.stringify(Json); // 將修改后的JSON寫回到請求體中
2.JMeter
在JMeter的時間戳可以直接使用JMeter自帶函數在body中獲取,當然也可以在BeanShell前置處理器中使用代碼獲取
/1000是因為JMeter默認生成的時間戳為13位時間戳,我們只需要10位即可。
導包(org.json為第三方jar包)
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.jmeter.config.*;
import org.json.*;
獲取請求傳入的body,將其轉化為Json對象
// 獲取請求
Arguments arguments = sampler.getArguments();
// 獲取請求中的body內容
Argument arg = arguments.getArgument(0);
// 獲取body的value,并將其轉化為JSONObject對象
JSONObject dataobj = new JSONObject(arg.getValue());
獲取變量并拼接
String TimeStamp = dataobj.optString("TimeStamp");
String AppKey = dataobj.optString("AppKey");
String Data = dataobj.optString("Data");
String secretKey = "a323f9b6-1f04-420e-adb9-b06ty67b0e63";
String str = AppKey + TimeStamp + Data + secretKey;
進行md5運算
sign = DigestUtils.md5Hex(str);
修改json對象的sign并轉換為字符串寫回body中
dataobj.put("Sign", sign); // 修改Sign
arg.setValue(dataobj.toString()); // 轉換為字符串并歇回request-body中
完整代碼:
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.jmeter.config.*;
import org.json.*;
/*
* 獲取請求傳入的body,將其轉化為Json對象
*/
// 獲取請求
Arguments arguments = sampler.getArguments();
// 獲取請求中的body內容
Argument arg = arguments.getArgument(0);
// 獲取body的value,并將其轉化為JSONObject對象
JSONObject dataobj = new JSONObject(arg.getValue());
/*
* 獲取變量并拼接字符串
*/
// 獲取變量
String TimeStamp = dataobj.optString("TimeStamp");
String AppKey = dataobj.optString("AppKey");
String Data = dataobj.optString("Data");
String secretKey = "a323f9b6-1f04-420e-adb9-b06ty67b0e63";
// 字符串拼接
String str = AppKey + TimeStamp + Data + secretKey;
/*
* 簽名,更新body
*/
sign = DigestUtils.md5Hex(str); // md5運算
dataobj.put("Sign", sign); // 修改Sign
arg.setValue(dataobj.toString()); // 轉換為字符串并寫回request-body中
三、v1接口
1.Postman
? 獲取請求參數并將body的參數轉換為json對象
var Json = JSON.parse(pm.request.body);
獲取時間戳并修改json對象
var ts = Date.parse(new Date()) / 1000 - 10;
Json.ts = ts;
去除sign參數本身,然后去除值是空的參數
var keys = [];
// 循環遍歷JSON
for (let k in Json ){
// 排除json中鍵位sign以及值為空的數據
if (k == 'sign' || !Json[k]){
continue;
}
keys.push(k); // 生成篩選后的key序列
}
排序
keys.sort();
拼接字符串
let keys_str = '';
for (let x of keys){
keys_str += `${x}=${Json[x]}&`; // 使用模版字符串進行拼接
}
keys_str = keys_str + "key=a323f9b6-1f04-420e-adb9-b06ty67b0e63";
進行md5運算并將生成的hash序列轉換為字母全大寫字符串
var strmd5= CryptoJS.MD5(keys_str).toString().toUpperCase();
修改json對象中sign并將md5對象寫回body中
Json.sign = strmd5;
pm.request.body.raw = JSON.stringify(Json);
完整代碼:
/*
v1加密規則:
1. 參與簽名運算的參數選用入參里邊value非空的參數
2. 參與簽名運算的參數按照ASCII順序排序
3. 組合方式:key=value通過&符連接
4. 最后加上key=secret
5. 使用32位md5簽名,sign的字母全大寫
*/
/*
* 獲取請求參數
*/
var Json = JSON.parse(pm.request.body);
var ts = Date.parse(new Date()) / 1000 - 10; // 獲取時間戳
Json.ts = ts; // 修改json
/*
* 去除sign參數本身,然后去除值是空的參數
*/
var keys = []; // 定義key序列
// 循環遍歷JSON
for (let k in Json ){
// 排除json中鍵位sign以及值為空的數據
if (k == 'sign' || !Json[k]){
continue;
}
keys.push(k); // 生成篩選后的key序列
}
/*
* 對請求參數排序
*/
keys.sort();
/*
* 拼接字符串
*/
let keys_str = '';
for (let x of keys){
keys_str += `${x}=${Json[x]}&`; // 使用模版字符串進行拼接
}
keys_str = keys_str + "key=a323f9b6-1f04-420e-adb9-b06ty67b0e63";
/*
* 簽名并更新body
*/
var strmd5= CryptoJS.MD5(keys_str).toString().toUpperCase(); // 調用方法進行md5運算并將生成的hash序列轉換為字母全大寫字符串
Json.sign = strmd5; // 修改Json
pm.request.body.raw = JSON.stringify(Json);
2.JMeter
同樣在body中使用內置函數定義時間戳ts
導包
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.jmeter.config.*;
import org.json.*;
獲取請求傳入的body,將其轉化為Json對象
// 獲取請求
Arguments arguments = sampler.getArguments();
// 獲取請求中的body內容
Argument arg = arguments.getArgument(0);
// 獲取body的value,并將其轉化為JSONObject對象
JSONObject dataobj = new JSONObject(arg.getValue());
獲取Json的key
// 創建list存儲body中的key值
List keyArry = new ArrayList();
// 生成迭代對象
Iterator iterator = dataObj.keys();
// 循環key,將其放入list
for (String key : iterator) {
if (!key.equals("sign") && !key.equals("Sign")) {
keyArry.add(key);
}
}
對list進行排序
Collections.sort(keyArry);
字符串拼接
String str = "";
for (String s : keyArry) {
// log.error(s);
String value = dataObj.optString(s);
// 剔除值為空或值為null的參數
if (!value.equals("") && !value.equals(null)) {
str = str+s+"="+ value+"&";
}
}
str = str + "key=a323f9b6-1f04-420e-adb9-b06ty67b0e63";
進行md5運算并轉換為字母全大寫
String sign = DigestUtils.md5Hex(str).toUpperCase();
修改json對象的sign并轉換為字符串寫回body中
dataobj.put("sign", sign); // 修改Sign
arg.setValue(dataobj.toString()); // 轉換為字符串并歇回request-body中
完整代碼:
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.jmeter.config.*;
import org.json.*;
/*
* 獲取請求傳入的body,將其轉化為Json對象
*/
// 獲取請求
Arguments arguments = sampler.getArguments();
// 獲取請求中的body內容
Argument arg = arguments.getArgument(0);
// 獲取body的value,并將其轉化為JSONObject對象
JSONObject dataObj = new JSONObject(arg.getValue());
/*
* 獲取Json的key進行排序
*/
// 創建list存儲body中的key值
List keyArry = new ArrayList();
// 生成迭代對象
Iterator iterator = dataObj.keys();
// 循環key,將其放入list
for (String key : iterator) {
if (!key.equals("sign") && !key.equals("Sign")) {
keyArry.add(key);
}
}
/*
* 對list進行排序
*/
Collections.sort(keyArry);
/*
* 循環list中的key,讀取對應的Value組成字符串
*/
String str = "";
for (String s : keyArry) {
String value = dataObj.optString(s);
// 剔除值為空或值為null的參數
if (!value.equals("") && !value.equals(null)) {
str = str+s+"="+ value+"&";
}
}
str = str + "key=a323f9b6-1f04-420e-adb9-b06ty67b0e63";
/*
* 簽名并更新body
*/
String sign = DigestUtils.md5Hex(str).toUpperCase(); // 進行md5運算并轉換為字母全大寫
dataobj.put("sign", sign); // 修改Sign
arg.setValue(dataobj.toString()); // 轉換為字符串并寫回request-body中
四、v2接口
1.Postman
將下載后的json導入到postman,進入Lib install請求
發送請求,該請求會將bundle.js寫入到全局變量中
獲取請求參數并將body的參數轉換為json對象
var Json = JSON.parse(pm.request.body);
獲取時間戳并修改json對象
var ts = Date.parse(new Date()) / 1000 - 10;
Json.ts = ts;
去除sign參數本身,然后去除值是空的參數
var keys = [];
// 循環遍歷JSON
for (let k in Json ){
// 排除json中鍵位sign以及值為空的數據
if (k == 'sign' || !Json[k]){
continue;
}
keys.push(k); // 生成篩選后的key序列
}
排序
keys.sort();
拼接字符串
let keys_str = '';
for (let x of keys){
keys_str += `${x}=${Json[x]}&`; // 使用模版字符串進行拼接
}
keys_str = keys_str.slice(0,-1); // 刪除最后一個&
導入剛才寫入到全局變量的js
eval(pm.globals.get("pmlib_code"));
由于私鑰過長,所以這里把私鑰的內容寫到環境變量中,私鑰內容可在pkcs8_rsa_private_key.pem查看(私鑰與公鑰可自行更換,在conf.ini中進行配置即可)
獲取私鑰
const privatekey = pm.environment.get("privatekey");
加密
const sha256withrsa = new pmlib.rs.KJUR.crypto.Signature({"alg": "SHA256withRSA"}); // 生成簽名對象并制定為SHA256withRSA類型
sha256withrsa.init(privatekey); // 初始化privatekey
sha256withrsa.updateString(keys_str); // 更新要簽名的數據
const sign = pmlib.rs.hextob64(sha256withrsa.sign()); // 簽名并轉換為Base64字符串
修改json對象中sign并將md5對象寫回body中
Json.sign = sign;
pm.request.body.raw = JSON.stringify(Json); // 將修改后的JSON轉換回字符串格式寫回到請求體中
完整代碼:
/*
v2加密規則:
1. 參與簽名運算的參數選用入參里邊value非空的參數
2. 參與簽名運算的參數按照ASCII順序排序
3. 使用private_key簽名
4. 使用SHA256withRSA進行簽名
*/
/*
* 獲取請求參數
*/
var Json = JSON.parse(pm.request.body);
var ts = Date.parse(new Date()) / 1000 - 10; // 獲取時間戳
Json.ts = ts; // 修改json
/*
* 去除sign參數本身,然后去除值是空的參數
*/
var keys = []; // 定義key序列
// 循環遍歷JSON
for (let k in Json ){
// 排除json中鍵位sign以及值為空的數據
if (k == 'sign' || !Json[k]){
continue;
}
keys.push(k); // 生成篩選后的key序列
}
/*
* 對請求參數排序
*/
keys.sort();
/*
* 拼接字符串
*/
let keys_str = '';
for (let x of keys){
keys_str += `${x}=${Json[x]}&`; // 使用模版字符串進行拼接
}
keys_str = keys_str.slice(0,-1); // 刪除最后一個&
/*
* 加密并更新body
*/
eval(pm.globals.get("pmlib_code")); // 導入寫入到全局變量的js
const privatekey = pm.environment.get("privatekey"); // 從環境變量獲取私鑰
const sha256withrsa = new pmlib.rs.KJUR.crypto.Signature({"alg": "SHA256withRSA"}); // 生成簽名對象并制定為SHA256withRSA類型
sha256withrsa.init(privatekey); // 初始化privatekey
sha256withrsa.updateString(keys_str); // 更新要簽名的數據
const sign = pmlib.rs.hextob64(sha256withrsa.sign()); // 簽名并轉換為Base64字符串
Json.sign = sign;
pm.request.body.raw = JSON.stringify(Json);
2.JMeter
同樣在body中使用內置函數定義時間戳ts,同時添加用戶定義的變量配置元件來存放私鑰
導包
import org.apache.jmeter.config.*;
import org.apache.commons.codec.digest.DigestUtils;
import org.json.*;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
獲取請求傳入的body,將其轉化為Json對象
// 獲取請求
Arguments arguments = sampler.getArguments();
// 獲取請求中的body內容
Argument arg = arguments.getArgument(0);
// 獲取body的value,并將其轉化為JSONObject對象
JSONObject dataobj = new JSONObject(arg.getValue());
獲取Json的key
// 創建list存儲body中的key值
List keyArry = new ArrayList();
// 生成迭代對象
Iterator iterator = dataObj.keys();
// 循環key,將其放入list
for (String key : iterator) {
if (!key.equals("sign") && !key.equals("Sign")) {
keyArry.add(key);
}
}
對list進行排序
Collections.sort(keyArry);
字符串拼接
String str = "";
for (String s : keyArry) {
// log.error(s);
String value = dataObj.optString(s);
// 剔除值為空或值為null的參數
if (!value.equals("") && !value.equals(null)) {
str = str+s+"="+ value+"&";
}
}
//刪除最后一個&
str = str.substring(0,str.length()-1);
讀取私鑰
? java中讀取私鑰需要刪除前面的“-----BEGIN PRIVATE KEY-----”和后面的“-----END PRIVATE KEY-----”,且需要key首尾連接中間無換行或空格。
String privateKeyString = vars.get("privateKey"); // 從用戶定義的變量中讀取私鑰
privateKeyString = privateKeyString.replace(" ", ""); // 刪除多余的空格
byte[] privateKeyBytes = Base64.getDecoder().decode(privateKeyString); // 將Base64解碼轉化為字符串
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes); // 根據給定的編碼密鑰創建一個新的 PKCS8EncodedKeySpec
PrivateKey privateKey = KeyFactory.getInstance("RSA").generatePrivate(keySpec); // 生成RSA的私鑰對象。
創建 Signature 對象并初始化
Signature signature = Signature.getInstance("SHA256withRSA"); // 生成SHA256withRSA的Signature 對象
signature.initSign(privateKey); // // 初始化簽署簽名的私鑰
更新要簽名的數據
signature.update(str.getBytes("UTF-8")); // 更新要簽名或驗證的字節
簽名
byte[] signatureBytes = signature.sign(); // 執行簽名
String sign = Base64.getEncoder().encodeToString(signatureBytes); // 將簽名結果轉換為 Base64 字符串
修改json對象的sign并轉換為字符串寫回body中
dataobj.put("sign", sign); // 修改Sign
arg.setValue(dataobj.toString()); // 轉換為字符串并歇回request-body中
完整代碼:
import org.apache.jmeter.config.*;
import org.apache.commons.codec.digest.DigestUtils;
import org.json.*;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
/*
* 獲取請求傳入的body,將其轉化為Json對象
*/
// 獲取請求
Arguments arguments = sampler.getArguments();
// 獲取請求中的body內容
Argument arg = arguments.getArgument(0);
// 獲取body的value,并將其轉化為JSONObject對象
JSONObject dataObj = new JSONObject(arg.getValue());
/*
* 獲取Json的key進行排序
*/
// 創建list存儲body中的key值
List keyArry = new ArrayList();
// 生成迭代對象
Iterator iterator = dataObj.keys();
// 循環key,將其放入list
for (String key : iterator) {
if (!key.equals("sign") && !key.equals("Sign")) {
keyArry.add(key);
// log.error(key);
}
}
// 對list進行排序
Collections.sort(keyArry);
/*
* 循環list中的key,讀取對應的Value組成字符串
*/
String str = "";
for (String s : keyArry) {
// log.error(s);
String value = dataObj.optString(s);
if (!value.equals("")) {
str = str+s+"="+ value+"&";
}
}
//刪除最后一個&
str = str.substring(0,str.length()-1);
/*
* 讀取私鑰
*/
String privateKeyString = vars.get("privateKey"); // 從用戶定義的變量中讀取私鑰
privateKeyString = privateKeyString.replace(" ", ""); // 刪除多余的空格
byte[] privateKeyBytes = Base64.getDecoder().decode(privateKeyString); // 將Base64解碼轉化為字符串
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes); // 根據給定的編碼密鑰創建一個新的 PKCS8EncodedKeySpec
PrivateKey privateKey = KeyFactory.getInstance("RSA").generatePrivate(keySpec); // 生成RSA的私鑰對象。
/*
* 讀創建 Signature 對象并初始化
*/
Signature signature = Signature.getInstance("SHA256withRSA"); // 生成SHA256withRSA的Signature 對象
signature.initSign(privateKey); // 初始化簽署簽名的私鑰
//
/*
* 更新要簽名的數據化
*/
signature.update(str.getBytes("UTF-8")); // 更新要簽名或驗證的字節
/*
* 簽名并更新body
*/
byte[] signatureBytes = signature.sign(); // 簽署所有更新字節的簽名
// 將簽名結果轉換為 Base64 字符串
String sign = Base64.getEncoder().encodeToString(signatureBytes); // 編碼為Base64字符串
dataobj.put("sign", sign); // 修改Sign
arg.setValue(dataobj.toString()); // 轉換為字符串并歇回request-body中
總結
以上是生活随笔為你收集整理的【Postman&JMeter】使用Postman和JMeter进行signature签名的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 征信报告简版和详细版有什么区别 有以下三
- 下一篇: ubuntu 22.04.1安装雷池开源