SpringBoot API加签

SpringBoot API加签_第1张图片

文章目录

    • 一. 签名数据存放
    • 二. 请求头说明
    • 三. 请求签名
    • 四. Postman自动加签脚本
    • 五. Postman 调试结果
    • 六. 服务端加签校验结果

一. 签名数据存放

  • 所有签名数据,一律存放在请求头中

二. 请求头说明

  • APP_TIMESTAMP
  • 时间戳,配合随机字符串防重复提交
  • 有效期为10分钟
  • APP_NONCE
  • 随机字符串,配合时间戳防重复提交
  • 随机字符串最大长度为12
  • 随机字符串15分钟内不可重复使用
  • APP_TENANT_CODE
  • APP_ID,约定下发的产品id, 此处指租户的TenantId
  • APP_SIGNATURE
  • 签名字符串
  • 签名字符串由上述几个属性值拼接获得

三. 请求签名

  • For Get/Delete Request

    • 取请求链接中的参数的键值对加请求头(APP_TIMESTAMP,APP_NONCE,APP_TENANT_CODE)进行顺排(按照Key值) , 最终得到待加密数据
  • For Post/Put Request

    • 取RequestBody的内容(组装为PARAMETER=RequestBody字符串的形式)加请求头(APP_TIMESTAMP, APP_NONCE, APP_TENANT_CODE)进行顺排(按照Key值), 最终得到待加密数据
  • 通用流程

    • 将待加密数据进行拼接(不要最后一个&)
key=value&key2=value2&key3=value3

例如

APP_NONCE=isj28d7h3ndw&APP_TENANT_ID=1&APP_TIMESTAMP=1637830481&projectId=1
  • 将排序后的字符串进行MD5加密(全大写) 得到APP_SIGNATURE的值,并将其设置到请求头中
    APP_SIGNATURE: 6299F89F4B9BE3A990008DDB7DC09037

四. Postman自动加签脚本

客户端WEB端对接逻辑可以根据此脚本进行改写

// =======================[ 工具方法定义区 ]===========================
// 生成随机字符串方法
function randomString(length, chars) {
    let result = '';
    for (let i = length; i > 0; --i) result += chars[Math.floor(Math.random() * chars.length)];
    return result;
}

// 获取排序字典
function getSortedMap(map) {
    let keys = [];
    for (let key of Object.keys(map)) {
        keys.push(key)
    }
    keys.sort();
    let newMap = new Map();
    keys.forEach(key => {
        newMap.set(key, map[key]);
    });
    return newMap;
}

// 获取排序字符串
function getSortedStr(map) {
    map = getSortedMap(map);
    // 初始化排序字符串
    let sortedStr = "";
    // 遍历集合
    for (let [key, value] of map) {
        sortedStr = sortedStr + key + "=" + value + "&";
    }
    sortedStr = sortedStr.substring(0, sortedStr.length - 1);
    return sortedStr;
}

// =======================[ 变量初始化区 ]===========================
// 获取租户编码
let tenantCode = pm.environment.get("tenantCode");
// 获取客户端类型
let appType = pm.environment.get("appType");
// 获取当前时间戳
let timestamp = Math.round(new Date().getTime());
// 获取12位随机字符串
let nonce = randomString(12, "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
// 初始化签名
let signature = "";
// 获取当前请求方法
let requestMethod = pm.request.method;
// 初始化排序字符串
let sortedStr = "";
// 初始化排序字典
let sortedMap = {
    "APP_NONCE": nonce,
    "APP_TENANT_CODE": tenantCode,
    "APP_TIMESTAMP": timestamp
};

// =======================[ 签名区 ]===========================
// 判断请求方法, 使用不同的签名逻辑
switch (requestMethod) {
    case "POST":
    case "PUT":
        // 获取requestBody
        let bodyRaw = pm.request.body.raw;
        // 获取请求协议
        let contentType = pm.request.getHeaders()["Content-Type"];
        // 未指定ContentType, 或者ContentType为application/json时才取body进行加密
        if(undefined === contentType || "application/json" === contentType){
            if ('' !== bodyRaw && null != bodyRaw) { 
                // 去除请求体的制表符与换行符  设置字典参数
                sortedMap["PARAMETER"] = pm.request.body.raw.replace(/[\r\n]/g, "").replace(/\ +/g, "");
            }
        }
        // 对象字段排序获取排序字符串
        sortedStr = getSortedStr(sortedMap);
        // MD5加密转大写
        signature = CryptoJS.MD5(sortedStr).toString().toUpperCase();
        break
    case "GET":
    case "DELETE":
        let list = pm.request.url.query;
        if(list.count() > 0){
            let paramsMap = list.map();
            for(let idx in paramsMap){
                let entry = paramsMap[idx];
                sortedMap[entry.key] = entry.value;
            }
        }
        // 对象字段排序获取排序字符串
        sortedStr = getSortedStr(sortedMap);
        // MD5加密转大写
        signature = CryptoJS.MD5(sortedStr).toString().toUpperCase();
        break;
}

// =======================[ 日志打印区 ]===========================
console.log("[ 请求方法 ] requestMethod :" + requestMethod);
console.log("[ 租户 ] tenantCode :" + tenantCode);
console.log("[ 客户端类型 ] appType :" + appType);
console.log("[ 时间戳 ] timestamp :" + timestamp);
console.log("[ 随机串 ] nonce :" + nonce);
console.log("[ 排序字符串 ] sortedStr :" + sortedStr);
console.log("[ 签名字符串 ] signature :" + signature);

// =======================[ 请求头封装区 ]===========================
pm.request.headers.upsert({
    key: 'APP_TENANT_CODE',
    value: tenantCode
});
pm.request.headers.upsert({
    key: 'APP_TIMESTAMP',
    value: timestamp
});
pm.request.headers.upsert({
    key: 'APP_NONCE',
    value: nonce
});
pm.request.headers.upsert({
    key: 'APP_TYPE',
    value: appType
});
pm.request.headers.upsert({
    key: 'APP_SIGNATURE',
    value: signature
});

五. Postman 调试结果

SpringBoot API加签_第2张图片

六. 服务端加签校验结果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FpfNZugM-1658495483303)(/tfl/pictures/202201/tapd_67839605_1641141150_78.png)]

你可能感兴趣的:(Spring,java,postman,开发语言)