apifox调用jar程序

embedded/2024/12/27 11:39:43/

背景:测试接口要用到签名,所以想通过apifox直接设置签名相关字段

解决方案:开始是准备些javascript脚本,但是一直存在依赖的方法找不到问题,后面知道可以调用java程序,简直方便多了

一、写java程序,并打出可执行的jar

我是现有的springboot程序上修改的,

1、先写生成签名的方法工具方法

import cn.hutool.core.util.StrUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.*;public class RSAUtil {private static final ObjectMapper objectMapper = new ObjectMapper();private static final String SIGNATURE_ALGORITHM = "SHA256withRSA";/*** 使用私钥对数据进行签名*/public static String sign(String data, PrivateKey privateKey) throws Exception {Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);signature.initSign(privateKey);signature.update(data.getBytes(StandardCharsets.UTF_8));byte[] signBytes = signature.sign();return Base64.getEncoder().encodeToString(signBytes);}/*** 从Base64编码字符串加载私钥*/public static PrivateKey loadPrivateKey(String base64PrivateKey) throws Exception {byte[] keyBytes = Base64.getDecoder().decode(base64PrivateKey);PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);KeyFactory keyFactory = KeyFactory.getInstance("RSA");return keyFactory.generatePrivate(spec);}/*** 从文件加载私钥*/public static PrivateKey loadPrivateKeyFromFile(String filePath) throws Exception {System.getProperty("user.dir");byte[] keyBytes = Files.readAllBytes(new File(filePath).toPath());PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);KeyFactory keyFactory = KeyFactory.getInstance("RSA");return keyFactory.generatePrivate(spec);}public static String buildDataToSign(String requestBody, long timestamp, String nonce, String sessionId) throws JsonProcessingException {StringBuilder content = new StringBuilder();if(StrUtil.isNotBlank(requestBody)){content.append("body=").append(requestBody.replaceAll("\\s+", "").trim()).append("&");}content.append("timestamp=").append(timestamp).append("&");content.append("nonce=").append(nonce).append("&");if(StrUtil.isNotBlank(sessionId)){content.append("sessionId=").append(sessionId).append("&");}return content.toString().substring(0, content.length() - 1);}public static String buildDataToSignForSort(String requestBody, long timestamp, String nonce, String sessionId) throws JsonProcessingException {// 将请求体转换为MapMap<String, Object> params = new LinkedHashMap();if(StrUtil.isNotBlank(requestBody)){params = objectMapper.readValue(requestBody.replaceAll("\\s+", "").trim(), LinkedHashMap.class);}params.put("timestamp", timestamp);params.put("nonce", nonce);if(StrUtil.isNotBlank(sessionId)){params.put("sessionId", sessionId);}SortedMap<String, Object> sortedParams = new TreeMap<>(params);StringBuilder content = new StringBuilder();for (String key : sortedParams.keySet()) {if ("sign".equals(key)) continue; // 排除签名本身if (sortedParams.get(key) != null) { // 忽略值为null的字段content.append(key).append("=").append(sortedParams.get(key)).append("&");}}String str= content.toString().substring(0, content.length() - 1); // 移除最后一个 &return str;}
}

2、写main方法,根据参数生成签名

@SpringBootApplication
public class TestApplication {public static void main(String[] args) {String rsaPrivateKey = "yourprivatekey";String requestBody = args[0];Long timestamp = StrUtil.isBlank( args[1]) ? null : Long.parseLong( args[1]);String nonce = args[2];String sessionId = null;if(args.length>3){sessionId = args[3];}try {// 构造待验签的数据String dataToVerify = RSAUtil.buildDataToSign(requestBody, timestamp, nonce, sessionId);PrivateKey privateKey = RSAUtil.loadPrivateKey(rsaPrivateKey);String genPrivateSignStr = RSAUtil.sign(dataToVerify, privateKey);System.out.println(genPrivateSignStr);} catch (Exception e) {throw new RuntimeException(e);}}
}

3、生成jar包:RSA.jar

可以通过命令行验证jar包是否正常,java -jar RSA .jar 参数等等

二、配置apifox

1、引入jar

找到设置-》外部程序,打开目录,然后把RSA.jar拷贝到这个目录下

2、配置环境变量

配置后会往这个里面设置值

3、编写前置操作的脚本

选择前置操作-》增加前置操作-》自定义脚本

// 获取当前时间戳(毫秒)
const timestamp = Date.now();// 生成随机数(nonce)
const nonce = btoa(Math.random().toString().slice(2)).slice(0, 16);// 检查是否需要 sessionId(例如通过环境变量或请求参数获取)
let sessionId = pm.variables.get('sessionId') || '';// 获取请求体内容
// const requestBody = JSON.stringify(pm.request.body.raw);
// const requestBodyRaw = pm.request.body.raw;
let requestBodyRaw = pm.request.body.raw;
// 检查 requestBodyRaw 是否为 null 或者仅包含空白字符
if (!requestBodyRaw || requestBodyRaw.trim() === '') {requestBodyRaw = ''; // 设置为空字符串
} 
const requestBody = typeof requestBodyRaw === 'string' ? requestBodyRaw.trim() : JSON.stringify(requestBodyRaw);// var requestBodyRaw2 = requestBodyRaw;
// // 确保 requestBody 是原始的 JSON 字符串,并且清理多余空白字符
// if (typeof requestBodyRaw === 'string') {
//     // 去除多余的空白字符(包括换行符和制表符)
//     requestBodyRaw2 = requestBodyRaw2.trim().replace(/\s+/g, ' ');//     // 如果 JSON 字符串中包含转义的双引号,尝试修复它们
//     requestBodyRaw2 = requestBodyRaw2.replace(/\\\"/g, '"');
// }const urlPathArray = pm.request.url.path;
// 定义你想要匹配的最后一级路径
const targetLastPath = 'login';
if (urlPathArray.length === 0) {console.log("URL 路径为空");
} else {// 获取最后一级路径const lastPath = urlPathArray[urlPathArray.length - 1];if (lastPath === targetLastPath) {sessionId  = ''; // 设置为空字符串} 
}const signatureBase64 = pm.execute("RSA.jar", [requestBody, timestamp, nonce, sessionId]);// 将签名设置到环境变量中,以便在后续请求中使用
pm.environment.set("X-Signature", signatureBase64);
pm.environment.set("X-Timestamp", timestamp);
pm.environment.set("X-Nonce", nonce);// 打印签名结果,用于调试
console.log("Signature: ", signatureBase64);

4、接口配置读取环境变量

5、点击接口发送即可以验证测试

可以在控制台看日志


http://www.ppmy.cn/embedded/149163.html

相关文章

C++ ——命名空间namespace

介绍 一般情况下&#xff0c;如果c中出现两个变量、函数名、类名完全相同时&#xff0c;就会产生冲突。解决命名冲突的办法传统的做法是重新使用不同的标识符。但又是这样做有时反而降低程序的可读性&#xff0c;因此c提供了第二种解决命名冲突的方法——命名空间。将这些名字相…

NFC 碰一碰发视频源码搭建技术详解,支持OEM

一、引言 NFC&#xff08;Near Field Communication&#xff09;近场通信技术以其便捷性和安全性在现代移动应用中得到了广泛应用。结合视频播放功能&#xff0c;实现 NFC 碰一碰发视频的应用场景&#xff0c;能够为用户带来全新的交互体验&#xff0c;例如在商场的产品推广、景…

【从算法小白到 csp-j 一等 第一节】枚举 + 模拟

【从算法小白到 csp-j 一等 第一节】枚举 模拟 内容提要1.枚举1.1枚举的定义1.2 [NOIP1998 普及组] 三连击&#xff08;1.00s&#xff0c;64.00MB&#xff09;题目背景题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1 解法 1.3 平面上的最接近点对&#xff08;1.00s&a…

主从复制架构介绍和主从复制配置案例

每一个数据库的业务都对应着一个前端的业务&#xff0c; 主从复制架构的必要性? 第一点是两个服务器如果有一台服务器出现故障&#xff0c;那么另一台服务器可以正常工作&#xff0c;以保障前端业务可以被正常访问&#xff0c;第二点是两个服务器可以共同去处理数据&#xff…

智能眼镜_AI眼镜基于紫光展锐W517方案定制开发

AI眼镜的国产方案搭载紫光展锐的W517穿戴芯片&#xff0c;该芯片采用12纳米制程技术&#xff0c;采用了1A752.0GHz和3A551.8GHz的大小核架构&#xff0c;配合无级变速系统调度与先进的3D SiP高集成技术&#xff0c;使得整体电路板尺寸较前一代产品缩小了40%。其高阶EPOP封装设计…

【java面向对象编程】第九弹----抽象类、接口、内部类

笔上得来终觉浅,绝知此事要躬行 &#x1f525; 个人主页&#xff1a;星云爱编程 &#x1f525; 所属专栏&#xff1a;javase &#x1f337;追光的人&#xff0c;终会万丈光芒 &#x1f389;欢迎大家点赞&#x1f44d;评论&#x1f4dd;收藏⭐文章 一、抽象类 1.1基本介绍 &…

flink-1.16 table sql 消费 kafka 数据,指定时间戳位置消费数据报错:Invalid negative offset 问题解决

1 背景 1.使用 flink-1.16 的 table sql 消费 kafka数据&#xff0c;并使用 sql 计算指标&#xff0c;然后写入 doris&#xff1b; 2.指标计算时&#xff0c;需要统计当日数据条数&#xff0c;考虑到作业异常退出被重新拉起时&#xff0c;需要从零点开始消费&#xff0c;所以…

虚幻引擎结构之UWorld

Uworld -> Ulevel ->Actors -> AActor 在虚幻引擎中&#xff0c;UWorld 类扮演着至关重要的角色&#xff0c;它就像是游戏世界的总指挥。作为游戏世界的核心容器&#xff0c;UWorld 包含了构成游戏体验的众多元素&#xff0c;从游戏实体到关卡设计&#xff0c;再到物…