Skip to content

签名规则

请求参数签名

注意

签名字符串中不能拥有 "\ 特殊符号,通常处理有嵌套对象的请求参数时,进行Json序列化会产生,如果不是在使用SDK,需要我们手动替换为空字符串,然后再进行签名。

将发送的所有数据假定位为集合M,将集合内非空的参数值按照参数名ASCII码从小到大排序,使用URL请求键值对参数方式进行拼接成字符串,类似key1=value1&key2=value2这样的格式。需要注意如下原则:

  • 将字符串中 "\ 特殊符号替换为空字符串''
  • 参数名ASCII码从小到大排序(字典序)
  • 如果参数值为空不进行签名
  • 参数名不区分大小写
  • 如果是嵌套参数,将嵌套的参数按上面的规则进行排序,然后转换为json字符串,然后参与排序
  • 进行验签时,sign字段不参与签名,将生成的签名与该sign值作校验

将上面生成的参数后追加上 sign=秘钥(追加后格式为 key1=value1&key2=value2&key=秘钥),然后将该字符串转换为大写,然后进行数据摘要算法计算出 sign值,并将sign值添加到请求中进行发送。

数据摘要支持MD5HmacSHA256两种,使用HmacSHA256时,key值作为秘钥

Java样例(使用SDK)

java
package cn.daxpay.single.sdk.util;

import cn.daxpay.single.sdk.param.channel.WeChatPayParam;
import cn.daxpay.single.sdk.param.pay.PayParam;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;

import java.util.Map;

/**
 * 参数签名测试类
 * @author xxm
 * @since 2024/2/7
 */
@Slf4j
public class PayParamSignTest {

    /**
     * 签名测试
     */
    @Test
    public void sign(){

        PayParam param = new PayParam();
        param.setClientIp("127.0.0.1");
        param.setNotNotify(true);

        param.setBizOrderNo("P0001");
        param.setTitle("测试接口支付");

        Map<String, String> map = PaySignUtil.toMap(param);
        log.info("转换为有序MAP后的内容: {}",map);
        String data = PaySignUtil.createLinkString(map);
        log.info("将MAP拼接字符串, 并过滤掉特殊字符: {}",data);
        String sign = "123456";
        data += "&sign="+sign;
        data = data.toUpperCase();
        log.info("添加秘钥并转换为大写的字符串: {}",data);
        log.info("MD5: {}",PaySignUtil.md5(data));
        log.info("HmacSHA256: {}",PaySignUtil.hmacSha256(data,sign));
    }

    /**
     * 多层嵌套对象签名测试
     */
    @Test
    public void sign2(){

        PayParam param = new PayParam();
        param.setClientIp("127.0.0.1");

        param.setBizOrderNo("P0002");
        param.setTitle("测试接口支付");
        WeChatPayParam weChatPayParam = new WeChatPayParam();
        weChatPayParam.setOpenId("6688812");
        weChatPayParam.setAuthCode("123456");
        param.setExtraParam(weChatPayParam);

        Map<String, String> map = PaySignUtil.toMap(param);
        log.info("转换为有序MAP后的内容: {}",map);
        String data = PaySignUtil.createLinkString(map).replaceAll("\\\"","").replaceAll("\"","");
        log.info("将MAP拼接字符串, 并过滤掉特殊字符: {}",data);
        String sign = "123456";
        data += "&sign="+sign;
        data = data.toUpperCase();
        log.info("添加秘钥并转换为大写的字符串: {}",data);
        log.info("MD5: {}",PaySignUtil.md5(data));
        log.info("HmacSHA256: {}",PaySignUtil.hmacSha256(data,sign));
    }

}

输出:

shell
转换为有序MAP后的内容: {bizOrderNo=P0001, clientIp=127.0.0.1, notNotify=true, reqTime=1715579269, title=测试接口支付}

将MAP拼接字符串, 并过滤掉特殊字符: bizOrderNo=P0001&clientIp=127.0.0.1&notNotify=true&reqTime=1715579269&title=测试接口支付

添加秘钥并转换为大写的字符串: BIZORDERNO=P0001&CLIENTIP=127.0.0.1&NOTNOTIFY=TRUE&REQTIME=1715579269&TITLE=测试接口支付&SIGN=123456

MD5: 4b60845df556be3c0f9be8643cea3d36

HmacSHA256: 69c61e6c539ebee56ae2b6de16f59b4d6b4da9e6809738ec7f7049daad1f845b

-----------------------------------------------------------------------------------------------------------------------------------------
转换为有序MAP后的内容: {bizOrderNo=P0002, clientIp=127.0.0.1, extraParam={"authCode":"123456","openId":"6688812"}, reqTime=1715579300, title=测试接口支付}

将MAP拼接字符串, 并过滤掉特殊字符: bizOrderNo=P0002&clientIp=127.0.0.1&extraParam={authCode:123456,openId:6688812}&reqTime=1715579300&title=测试接口支付

添加秘钥并转换为大写的字符串: BIZORDERNO=P0002&CLIENTIP=127.0.0.1&EXTRAPARAM={AUTHCODE:123456,OPENID:6688812}&REQTIME=1715579300&TITLE=测试接口支付&SIGN=123456

MD5: 44d81601494e7d9bc453c08137326689

HmacSHA256: 471c3612ee8b177bfce2c7752323c8d5b92b5605558d4bc8906dcf276d3022d3

响应参数验签

注意

响应参数验签时,通常我们接口返回的类型会是公共响应参数<业务响应参数>的格式,签名规则基本与请求参数验签一致,不过不是将返回参数整体进行验签, 而是只将返回参数中的业务响应数据进行验签。

通知消息验签

注意

通知消息验签时,规则与请求完全参数一致。

本文档内容版权属于济南易杯光年软件技术有限公司