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);