签名算法

在调用接口时需要计算当前调用参数的相关签名,并至于请求头部。

参与签名的数据如下:

  • 请求头部中的AppKey(X-AK)、时间戳(X-TS)、随机数(X-NONCE)
  • 请求消息中的消息体,并且key值为'body',为空则不参与签名
  • 请求消息的query参数,并且key值为'params',为空则不参与签名

签名步骤

第一步:将需要签名的字段按照key1=value1&key2=value2&key3=value3的形式拼接成字符串,注意 在拼接前需要按照key的ASCII码从小到大排序(升序),key区分大小写

第二步:对第一步拼接的字符串尾部拼接提供密钥AppSecret,得到SignValue字符串

第三步:对第二步拼接得到的SignValue字符串进行md5(小写)

第四步:将第三步计算得到的签名添加至请求头中的签名中(X-SIGN)

签名实现(Postman脚本)

// 平台ak和sk 
let appKey = 'BFGZRLWn' 
let appSecret = '66eef434789131c8f6bae20641bb4dc0692dffd3'

// 6位随机数和时间戳
let nonce = Math.floor(Math.random() * (999999 - 100000)) + 100000;
let timestamp = Math.round(Date.now());

let API_HEADER_APPKEY = 'X-AK';
let API_HEADER_TIMESTAMP = 'X-TS';
let API_HEADER_NONCE = 'X-NONCE';
let API_HEADER_SIGN = 'X-SIGN';

// 设置请求头
pm.request.headers.add({ key: API_HEADER_APPKEY, value: appKey })
pm.request.headers.add({ key: API_HEADER_TIMESTAMP, value: timestamp })
pm.request.headers.add({ key: API_HEADER_NONCE, value: nonce })

// 签名map
const signMap = new Map();
signMap.set(API_HEADER_APPKEY, appKey);
signMap.set(API_HEADER_TIMESTAMP, timestamp);
signMap.set(API_HEADER_NONCE, nonce);

let body = pm.request.body;
if(typeof body != "undefined" && body != null && body != ""){
    signMap.set('body',body);
}

let params = pm.request.url.query
if(typeof params != "undefined" && params != null && params != ""){
    signMap.set('params', params);
}

// 取出key按照ASCII码从小到大排序(升序)
let keys = Array.from(signMap.keys());
keys.sort();

// 转成键值对
let linkStringArray = [];
for (let i = 0, len = keys.length; i < len; i++) {
    let key = keys[i];
    linkStringArray.push(key + '=' + signMap.get(key))
}

// 拼接并追加密钥
let stringSignTemp = linkStringArray.join('&') + appSecret;
console.log("signtempstring===:", stringSignTemp);

// 计算签名
let sign = CryptoJS.MD5(stringSignTemp).toString().toLowerCase();
console.log("sign====:", sign);

// 签名写入header
pm.request.headers.add({ key: API_HEADER_SIGN, value: sign })

签名实现(Java部分代码)

private HashMap<String, String> createSignMap(HttpServletRequest request) {
        HashMap<String, String> signMap = new HashMap<>();

        // 请求头
        signMap.put(OpenApiHeader.APPKEY, HttpUtil.getHeader(request, OpenApiHeader.APPKEY));
        signMap.put(OpenApiHeader.TIMESTAMP, HttpUtil.getHeader(request, OpenApiHeader.TIMESTAMP));
        signMap.put(OpenApiHeader.NONCE, HttpUtil.getHeader(request, OpenApiHeader.NONCE));

        RequestReaderHttpServletRequestWrapper requestWrapper = (RequestReaderHttpServletRequestWrapper) request; ;
        String body = requestWrapper.getBodyConent();
        if (StrUtil.isNotBlank(body)) {
            signMap.put("body", body);
        }

        // query参数
        // 中文的查询参数在http请求时会进行urlencode编码后进行传递,在获取时特需要解码拿到最原始的数据
        String queryString = request.getQueryString();
        String params = URLDecoder.decode(queryString, StandardCharsets.UTF_8);
        if (StrUtil.isNotBlank(params)) {
            signMap.put("params", params);
        }
        return signMap;
    }

    private String calculateSign(HashMap<String, String> signMap, String appSecret) {
        StringBuilder toSignBuilder = new StringBuilder();
        List<String> keys = signMap.keySet().stream().sorted().collect(Collectors.toList());

        for (int i = 0; i < keys.size(); i++) {
            if (i != 0) {
                toSignBuilder.append("&");
            }
            String key = keys.get(i);
            toSignBuilder.append(key);
            toSignBuilder.append("=");
            toSignBuilder.append(signMap.get(key));
        }

        // 最后追加盐
        toSignBuilder.append(appSecret);
        String signString = toSignBuilder.toString();

        log.info("待签名字符串:" + signString);
        return MD5.create().digestHex(signString);
    }

results matching ""

    No results matching ""