签名规则

1.使用URL键值对的格式(即key1=value1&key2=value2…)参数名ASCII码从小到大排序(字典序)拼接成字符串stringA;

2.在stringA最后拼接上company_secret得到stringSignTemp字符串,并对stringSignTemp进行MD5运算,再将得到的字符串所有字符转换为大写,得到sign值signValue;

3.传参的字段sign是通过签名规则生成的,但不参加签名计算;company_secret参加签名计算,但不在传参字段之列。

举例说明

以网络货运的【车辆备案】接口为例,假设要传的参数为

content:01,04,4403162320,33903671,1165.05,20170803,81171643890998027896,27E4
company_key:44167fc5-c8e9-4ba0-9224-656345f26d5b
department_id:a013476188ce4bcb99b1edb0ed73361f
nonce_str:123456
sign:(完成签名计算后填入)

company_secret为

company_secret:f21e6d76-b47e-4c62-96d1-63a19a5f4116

第一步,给传参字段排序拼接(不含sign)

content=01,04,4403162320,33903671,1165.05,20170803,81171643890998027896,27E4&company_key=44167fc5-c8e9-4ba0-9224-656345f26d5b&department_id=a013476188ce4bcb99b1edb0ed73361f&nonce_str=123456

第二步,在第一步拼接结果的最后拼接上company_secret

content=01,04,4403162320,33903671,1165.05,20170803,81171643890998027896,27E4&company_key=44167fc5-c8e9-4ba0-9224-656345f26d5b&department_id=a013476188ce4bcb99b1edb0ed73361f&nonce_str=123456&company_secret=f21e6d76-b47e-4c62-96d1-63a19a5f4116

第三步,使用MD5为第二步拼接结果的字符串加密,取32位大写的值,作为sign的值

9212B21EE89BBCE83A1CFD2753093516

第四步,最终需要传参的字段key:value即为

content:01,04,4403162320,33903671,1165.05,20170803,81171643890998027896,27E4
company_key:44167fc5-c8e9-4ba0-9224-656345f26d5b
department_id:a013476188ce4bcb99b1edb0ed73361f
nonce_str:123456
sign:9212B21EE89BBCE83A1CFD2753093516

假设要传的参数为:

content = "01,04,4403162320,33903671,1165.05,20170803,81171643890998027896,27E4,"

company_key = "26bbab36-8c2d-44c3-a7fd-2ec6a5d423c7"

nonce_str = "000000"(6位随机字符串)

用于加密的company_secret为:

company_secret = "5a35328a-15ba-4f0b-b32c-afe56c6589c7"

第一步:排序为:stringA = company_key=26bbab36-8c2d-44c3-a7fd-2ec6a5d423c7&content=01,04,4403162320,33903671,1165.05,20170803,81171643890998027896,27E4,&nonce_str=000000

第二步:拼接:stringSignTemp=stringA + “&company_secret=5a35328a-15ba-4f0b-b32c-afe56c6589c7",md5加密后再转换为大写,最终结果为:

FD4667ABF01B264278586E3C15FDF96C

Python 示例代码

def sign_action(key, parameters):
    sortedParameters = sorted(
        parameters.items(), key=lambda parameters: parameters[0])
    canonicalizedQueryString = ''
    for (k, v) in sortedParameters:
        if v or v == 0:
            canonicalizedQueryString += '&' + str(k).strip() + '=' + str(v).strip()
    tempstring = canonicalizedQueryString[1:] + '&' + 'company_secret=' + str(key)
    signature = md5(tempstring.strip().encode()).hexdigest().upper()
    print(tempstring)
    print(signature)
    return signature

Java 示例代码

private static Object invokeFee(@NotNull Map<String, String> kvMap,
                                    @NotNull Map<String, Object> ignore,//不参与加密数据
                                    @NotNull String url,
                                    int method) {
        kvMap.put("company_key", AppPropertyUtils.getKey());
        //6位随机字符串
        kvMap.put("nonce_str", AppUitls.randomStr(6));

        Map<String, Object> resultMap = new HashMap<>();
        ArrayList<String> keys = Lists.newArrayList(kvMap.keySet());
        Collections.sort(keys, new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                /*
                 * *按ASCII表排序
                 * *可以看到return有个? :表达式。
                 * *解释一下
                 * *o1.compareToIgnoreCase(o2) == 0是先看看不区分大小写对比出来的值是否等于0,
                 * *如果=0,返回-o1.compareTo(o2),前面加-是让小写在大写前面
                 * *如果不等于0,返回o1.compareToIgnoreCase(o2)
                 */
                return (o1.compareToIgnoreCase(o2) == 0 ? -o1.compareTo(o2) : o1.compareToIgnoreCase(o2));
            }
        });
        try {
            StringBuilder params = new StringBuilder();
            for (String key : keys) {
                params.append(key);
                params.append("=");
                params.append(kvMap.get(key));
                params.append("&");
                resultMap.put(key, kvMap.get(key).toString());
            }
            params.append(URLEncoder.encode("company_secret", "utf-8"));
            params.append("=");
            params.append(URLEncoder.encode(AppPropertyUtils.getSecret(), "utf-8"));

            logger.info("参数排序后为: " + params.toString());
            String md5 = Md5.getEncode(params.toString());
            resultMap.put("sign", md5);
            logger.info("======>>加密后签名: " + md5);
        } catch (Exception e) {
            logger.error("======>>签名失败:", e);
            return ErrorResps.SIGN_ERROR.get();
        }

        if (ignore != null) resultMap.putAll(ignore);
        Object content = null;
        try {
            if(method==HTTP_GET){
                String entity = HttpHelper.doGetEntity(url, resultMap);
                content = new JacksonJsonParser().parseMap(entity);
            }else{
                ResponseContent postEntity = HttpHelper.postEntity(url, resultMap);
                content = new JacksonJsonParser().parseMap(postEntity.getContent());
            }
            logger.info("feecloud reponse: " +content);
        } catch (Exception e) {
            logger.error("invoke feecloud failed: ", e);
            return ErrorResps.INVOKE_FEECLOUD_FAILED.get();
        }

        logger.info("======费耘返回数据: " + content);

        return content;
    }

results matching ""

    No results matching ""