接口签名和postman预处理生成签名

news2024/11/24 3:42:41

nestjs后端代码

controller

 @Get('md5hmacSHA1b64')
  postMd5hmacSHA1b64(@Req() request: Request, @Query() query) {
    // 获取GET请求参数
    const queryParamsMap = new Map(Object.entries(query));
    return this.handleMd5hmacSHA1b64(queryParamsMap, request);
  }

  @Post('md5hmacSHA1b64')
  @UseInterceptors(NoFilesInterceptor())
  getMd5hmacSHA1b64(@Req() request: Request, @Body() formData) {
    //@Body() formData 支持 x-www-form-urlencoded 和 application/json 类型的请求, 但是不支持普通表单 form-data
    //form-data支持文件上传, x-www-form-urlencoded不支持文件上传
    //使用 @UseInterceptors(NoFilesInterceptor()) 让@Body()支持form-data键值对形式的非文件上传场景
    console.log('formData:', formData);
    //提取formData的键值对
    const query2 = new Map(Object.entries(formData));
    console.log('query2:', query2);
    return this.handleMd5hmacSHA1b64(query2, request);
  }

  private handleMd5hmacSHA1b64(
    queryParamsMap: Map<string, any>,
    request: Request,
  ) {
    //获取header列表
    //const queryHeadersMap = new Map(Object.entries(request.headers));
    //queryHeadersMap 只取出指定header accessKeyId nonce timestamp
    const queryHeadersMap2 = new Map(
      Object.entries(request.headers).filter(
        (item) =>
          item[0] === 'accesskeyid' ||
          item[0] === 'nonce' ||
          item[0] === 'timestamp' ||
          item[0] === 'sign',
      ),
    );
    //queryHeadersMap2 的 key  accesskeyid 替换为 accessKeyId
    queryHeadersMap2.forEach((value, key) => {
      if (key === 'accesskeyid') {
        queryHeadersMap2.set('accessKeyId', value);
        queryHeadersMap2.delete('accesskeyid');
      }
    });
    //将上面两个map合并
    const allMap = new Map([...queryParamsMap, ...queryHeadersMap2]);
    return this.epgService.md5hmacSHA1b64(allMap);
  }

private handleMd5hmacSHA1b64(
    queryParamsMap: Map<string, any>,
    request: Request,
  ) {
    //获取header列表
    //const queryHeadersMap = new Map(Object.entries(request.headers));
    //queryHeadersMap 只取出指定header accessKeyId nonce timestamp
    const queryHeadersMap2 = new Map(
      Object.entries(request.headers).filter(
        (item) =>
          item[0] === 'accesskeyid' ||
          item[0] === 'nonce' ||
          item[0] === 'timestamp' ||
          item[0] === 'sign',
      ),
    );
    //queryHeadersMap2 的 key  accesskeyid 替换为 accessKeyId
    queryHeadersMap2.forEach((value, key) => {
      if (key === 'accesskeyid') {
        queryHeadersMap2.set('accessKeyId', value);
        queryHeadersMap2.delete('accesskeyid');
      }
    });
    //将上面两个map合并
    const allMap = new Map([...queryParamsMap, ...queryHeadersMap2]);
    return this.epgService.md5hmacSHA1b64(allMap);
  }

service代码

md5hmacSHA1b64(allMap: Map<string, any>) {
    const accessKeyId =process.env.ACCESS_KEY_ID;
    const accessKeySecret = process.env.ACCESS_KEY_SECRET;

    console.log(allMap);
    //遍历allMap列表,拷贝到headerMap
    const sign = allMap.get('sign');
    console.log("sign", sign)
    const headerMap = {};
    for (const key of allMap.keys()) {
      // 去掉名为sign的key
      if (key !== 'sign') {
        headerMap[key] = allMap.get(key);
      }
    }
    console.log('headerMap=', headerMap)
    //accessKeyId 替换为约定的accessKeyId
    headerMap['accessKeyId'] = accessKeyId;

    //对headerMap按字母排序
    const sortHeaderMap = {};
    Object.keys(headerMap)
        .sort()
        .forEach((key) => {
          sortHeaderMap[key] = headerMap[key];
        });
    console.log('sortHeaderMap=', sortHeaderMap);

    //对排序后的header拼接字符串 形如 key1=value1&key2=value2&key3=value3的形式,最后一项没有&
    let str = '';
    for (const key in sortHeaderMap) {
      str += key + '=' + sortHeaderMap[key] + '&';
    }
    str = str.substring(0, str.length - 1);

    //base64
    const base64 = CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(str));
    //hmacsha1
    const hmacsha1 = CryptoJS.HmacSHA1(base64, accessKeySecret);
    //md5
    const md5 = CryptoJS.MD5(hmacsha1).toString();
    //判断sign==md5 若相等 返回check 字段为ok
    return {
      str,
      md5hmacSHA1b64: md5,
      check: sign === md5?'ok':'no',
    };
  }

postman接口

header定义

pre-Request预处理脚本

// 辅助函数:补零
function padZero(num) {
    return num.toString().padStart(2, '0');
}
// 生成16位随机数,用于nonce
function generateRandom16bit() {
    return Math.random().toString(16).substring(2, 18);
}
//验证请求GET POST ok
let accessKeyId = "UC1"; //签名Key
let accessKeySecret = "UC2"; //签名secret
//let accessKeyId = pm.request.headers.get("accessKeyId");

let param = {};
console.log("param:",param)


// 获取当前时间戳
const now = new Date();
// 时间戳 格式化为指定样式  yyyyMMddHHmmss
const formattedTimestamp = 
    now.getFullYear().toString() + // 年份
    padZero(now.getMonth() + 1) + // 月份,注意月份是从0开始的,所以加1
    padZero(now.getDate()) +
    padZero(now.getHours()) +
    padZero(now.getMinutes()) +
    padZero(now.getSeconds());

//16位随机数
let nonce = generateRandom16bit()

//头部参数
param['accessKeyId']=accessKeyId
param['nonce']=nonce
param['timestamp']=formattedTimestamp

//Get 参数
let queryParam = pm.request.url.query.members;
console.log("queryParam:",queryParam)
for (let i in queryParam){
    param[queryParam[i].key] = queryParam[i].value;
}
//POST参数
let postParam = request.data;
console.log("postParam:",postParam)
if(typeof(postParam) == "string"){
    try{
        let dataJson = JSON.parse(postParam);
        // 将解析后的数据合并到param对象中
        Object.assign(param, dataJson);
    }catch(err){
        console.log(err)
    }
}else{
    Object.assign(param, postParam);
}

console.log("allParam:",param)
//Post
//取key
var keys = [];
for (let k in param){
    if (k == 'sign'){
        continue;
    }
    keys.push(k); 
}
//排序
keys.sort();

//取value
var kv = [];
for (let k of keys){
    kv.push(k + '=' + param[k]) 
    
}

//拼接
var str = kv.join('&');

console.log("str=",str)
//签名计算算法md5(hmacsha1(base64(str)))
const base64 = CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(str));
const hmacsha1 = CryptoJS.HmacSHA1(base64, accessKeySecret);
const md5 = CryptoJS.MD5(hmacsha1).toString();

//设置环境变量
postman.setEnvironmentVariable("nonce", nonce);
postman.setEnvironmentVariable("timestamp", formattedTimestamp);
postman.setEnvironmentVariable("sign", md5);

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1798237.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Redis】解决 Redis 运行在 Protected Mode 下的 DENIED 错误:消除 Redis 受保护模式的完美方案

【Redis】解决 Redis 运行在 Protected Mode 下的 DENIED 错误&#xff1a;消除 Redis 受保护模式的完美方案 大家好 我是寸铁&#x1f44a; 总结了一篇【Redis】解决 Redis 运行在 Protected Mode 下的 DENIED 错误&#xff1a;消除 Redis 受保护模式的完美方案✨ 喜欢的小伙伴…

RAG 查询检索模块 - 检索 - Pinecone 混合检索方案

虽然向量检索有助于检索给定查询的语义相关块&#xff0c;但它有时在匹配特定关键字词方面缺乏准确性。 为了解决这个问题&#xff0c;混合检索是一种解决方案。该策略充分利用了矢量搜索和关键字搜索等不同检索技术的优势&#xff0c;并将它们智能地组合在一起。使用这种混合…

Linux驱动开发笔记(四)设备树进阶及GPIO、Pinctrl子系统

文章目录 前言一、设备树的进阶知识1. 追加/修改节点内容2.chosen子节点3. 获取设备树节点信息3.1 of_find_node_by_path( )函数3.2 of_find_node_by_name( )函数3.3 of_find_node_by_type( )函数3.4 of_find_compatible_node( )函数3.5 of_find_matching_node_and_match( )函数…

如何将照片从Android传输到笔记本电脑?

目前全球大部分照片都是由手机拍摄的。唯一的问题是这些照片会占用您的内部存储或 SD 卡上的大量空间。如果您的Android设备存储空间不足&#xff0c;您可能会被迫将照片从Android手机传输到笔记本电脑。您访问此网站只是因为您想了解如何将图片从Android传输到笔记本电脑。 如…

Ubuntu24.04开发环境配置

目录 0. 前言1. 宇宙最强编辑器&#xff08;暂定&#xff09;vscode的安装与配置1.1 下载安装1.2 用户配置和常用插件 2. C/C环境配置3. git配置4. MySQL配置5. Java环境配置 0. 前言 本篇博客主要介绍Ubuntu24.04中的开发环境等配置。 1. 宇宙最强编辑器&#xff08;暂定&am…

在大模型AI的下一个战场,为中小创新企业重构竞争格局

麦肯锡预计到2030年前&#xff0c;AI有望为全球经济贡献25.6万亿美元的价值&#xff0c;其中生成式AI的贡献高达7.6万亿美元。自2023年“百模大战”以来&#xff0c;基础大模型的“战事”已经进入尾声&#xff0c;大模型正在“卷向”产业和行业&#xff0c;越来越多的创新企业正…

【每日刷题】Day58

【每日刷题】Day58 &#x1f955;个人主页&#xff1a;开敲&#x1f349; &#x1f525;所属专栏&#xff1a;每日刷题&#x1f34d; &#x1f33c;文章目录&#x1f33c;​​​​​​​ 1. 3038. 相同分数的最大操作数目 I - 力扣&#xff08;LeetCode&#xff09; 2. 868. …

24年北京网安大会是AI驱动安全?还是驱动安全股票全员下跌?

AI驱动安全&#xff0c;网安一哥疯狂转发 吉祥学安全知识星球&#x1f517;除了包含技术干货&#xff1a;Java代码审计、web安全、应急响应等&#xff0c;还包含了安全中常见的售前护网案例、售前方案、ppt等&#xff0c;同时也有面向学生的网络安全面试、护网面试等。 2024年6…

Vue --关于传递参数

多参数传递的两种方法&#xff1a; 第一种&#xff1a;params方法&#xff08;此方法传递不会在URL路径中显示拼接&#xff09; 传递参数&#xff1a; this.$router.push({name: "home",params:{key:1} })接收参数&#xff1a; created() {// 获取参数console.log…

whistle手机抓包

环境&#xff1a;whistle&#xff1a;2.9.59 whistle手机抓包&#xff08;ios可以抓小程序的包&#xff1b;安卓机不能抓小程序的包&#xff0c;但是小程序的有开发者工具就够用了&#xff09; 以安卓手机为例&#xff08;手机跟电脑要连同一个wifi&#xff09; 1.电脑安装w…

香港优才计划线上申请10大步骤,2024年流程截图,diy照做就可以

我是糖爸&#xff0c;已获批香港优才。10个步骤申请香港优才真的很简单&#xff0c;因为现在入境处只接受线上申请啦&#xff0c;你自己上传资料就可以&#xff0c;找中介也是你自己准备资料给他帮忙上传&#xff0c;何不自己动手上传呢&#xff0c;省个几万。 10大步骤分别是&…

2024年【起重机司机(限桥式起重机)】考试试卷及起重机司机(限桥式起重机)证考试

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2024年【起重机司机(限桥式起重机)】考试试卷及起重机司机(限桥式起重机)证考试&#xff0c;包含起重机司机(限桥式起重机)考试试卷答案和解析及起重机司机(限桥式起重机)证考试练习。安全生产模拟考试一点通结合国家…

fastadmin按钮级别权限控制实现

1.菜单规则得存在。 2.html代码增加对应控制 3.js代码增加对应路由标志 <div class"panel panel-default panel-intro"><div class"panel-heading">{:build_heading(null,FALSE)}<ul class"nav nav-tabs" data-field"sta…

numpy入门笔记

学习参考&#xff1a; 菜鸟教程 numpy入门博客 numpy入门视频 NumPy安装 默认情况使用国外线路&#xff0c;国外太慢&#xff0c;我们使用清华的镜像 pip3 install numpy scipy matplotlib -i https://pypi.tuna.tsinghua.edu.cn/simple一、创建数组 numpy.array(object, dt…

【K8s】专题四(7):Kubernetes 控制器之 CronJob

以下内容均来自个人笔记并重新梳理&#xff0c;如有错误欢迎指正&#xff01;如果对您有帮助&#xff0c;烦请点赞、关注、转发&#xff01;欢迎扫码关注个人公众号&#xff01; 目录 一、基本介绍 二、工作原理 三、相关特性 四、资源清单&#xff08;示例&#xff09; 五…

一图文看懂oracle数据库的安装与卸载

oracle数据库安装与卸载 1、卸载 对于已经安装过oracle数据库的主机&#xff0c;一般卸载起来比较麻烦&#xff0c;需要卸载大致四个地方&#xff0c;分别是关闭应用的服务、删除相关注册表、删除路径以及删除安装的位置&#xff0c;最后就需要重启主机。 前提&#xff0c;在…

从零开始:如何在直播应用中集成美颜SDK和美颜插件

本篇文章&#xff0c;小编将详细介绍如何从零开始&#xff0c;在直播应用中集成美颜SDK和美颜插件。 一、准备工作 确定需求 在开始集成美颜SDK之前&#xff0c;首先需要明确需求。考虑以下几个问题&#xff1a; 直播应用的目标用户是谁&#xff1f; 需要集成哪些美颜功能&…

图的相关种类

目录 数据类型 存储结构 邻接矩阵表示法 无向图 邻接矩阵表示 有向图 网 实现 邻接矩阵表示 存储结构 创建无向图 优点 缺点 邻接表法表示 表示无向图 表示有向图 存储结构 无向网 特点 十字链表与多重表 十字链表 存储结构 多重表 存储结构 数据类型 存…

IDEA使用阿里通义灵码插件

在这个AI火热的时代&#xff0c;纯手工写代码已经有点out了&#xff0c;使用AI插件可以帮我们快速写代码&#xff0c;起码能省去写那些简单、重复性的代码&#xff0c;大大提高编码效率&#xff0c;在这里我推荐使用阿里的通义灵码 注册安装 安装注册好后&#xff0c;打开我们…

室内外融合定位是如何做到成为定位领域的新宠

在信息化高速发展的今天&#xff0c;定位技术已成为人们生活和工作中不可或缺的一部分。随着物联网、智慧城市等领域的蓬勃发展&#xff0c;传统的单一定位方式已无法满足复杂多变的环境需求。在这样的背景下&#xff0c;室内外融合定位技术应运而生&#xff0c;以其独特的优势…