当前位置: 首页 > article >正文

apifox调用jar程序

背景:测试接口要用到签名,所以想通过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 {
        // 将请求体转换为Map
        Map<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.kler.cn/a/456555.html

相关文章:

  • Linux-----进程处理(子进程创建)
  • 【VBA】EXCEL - VBA 创建 Sheet 表的 6 种方法,以及注意事项
  • 解决springdoc-openapi-ui(Swagger3)跳转默认界面问题
  • MySQL 中存储金额数据一般使用什么数据类型
  • XIAO Esp32S3制作网络摄像头——音频获取
  • jangow靶机
  • 功能测试和接口测试
  • 总结-常见缓存替换算法
  • String的认识和使用
  • 【RK3568笔记】Android适配红外遥控器
  • 虚拟机配置网络(nat)
  • Windows 安装 Jenkins 教程
  • 敏捷开发Scrum的深入理解和实践
  • 开源轮子 - EasyExcel02(深入实践)
  • .net core 的文件操作
  • HTML 标签页(Tabs)详细讲解
  • ISDP010_基于DDD架构实现收银用例主成功场景
  • 探索 Java 微服务的新趋势:现代工具与最佳实践
  • 【elementplus】中文模式
  • 【微信小程序】4plus|搜索框-历史搜索 | 我的咖啡店-综合实训
  • yarn install 安装报错:Workspaces can only be enabled in private projects.
  • 用 Unity 引擎,了解其核心概念、组件、资源、脚本、编辑器等功能,能够独立开发多平台的游戏或应用
  • 一种基于XC7V690T的在轨抗单粒子翻转系统(一)
  • IDEA2020的一些有用的功能
  • Java 溯本求源之基础(三十)——封装,继承与多态
  • STM32开发笔记123:使用STM32CubeProgrammer下载程序