请求参数里有Query(查询参数),如何计算签名

更新时间:2024.08.22

为了方便大家理解,我们将使用测试的私钥,通过命令行形式调用“委托营销-查询合作关系列表"接口,一步一步介绍如何请求参数里有Query(查询参数),如何计算签名。强烈建议你使用测试的公私钥,按照本文实际操作一下,如果算出来的签名和文档的一致则说明计算无误。实际业务中请替换为你的真实的参数。 alt text
以委托营销-查询合作关系接口为例,查询参数需要在URL后面通过?拼接请求参数,且多个请求参数需要用&链接,且query参数中的partner参数和authorized_data参数需要做urldecode处理,

假设你的qurey参数如下图所示,我们将一步步演示如何计算签名

1limit=5
2offset=10
3authorized_data={"business_type":"FAVOR_STOCK", "stock_id":"2433405"}
4partner={"type":"APPID","appid":"wx4e1916a585d1f4e9","merchant_id":"2480029552"}

# 1. 准备

商户需要拥有一个微信支付商户号,并通过超级管理员账号登录商户平台,获取商户API证书,可以参考如何获取商户API证书 (opens new window)。 商户申请商户 API 证书时,证书工具会生成商户私钥,并保存在本地证书文件夹的文件apiclient_key.pem中。私钥也可通过工具从商户的 p12 证书中导出。请妥善保管好商户私钥文件。请注意计算签名需要用到的是商户API证书而不是平台证书,请不要搞混。

商户号:1900007291

证书序列号:408B07E79B8269FEC3D5D3E6AB8ED163A6A380DB

API证书私钥:你需要将以下文件保存为pem格式,为了避免大家和自己的真实的公私钥混淆,此处将其保存为了apiclient_test_key.pem,这只是一个示例密钥,实际上并不可用

-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEAptpm+qvIDCh/9wjU26SQCK26ogYkBhDrYxnAaw2JbbBsp1oD bHKk+1r381NeBUG2HEFAuU+Fr72u5ot3yKdzoF/FajAzQNKnm569/D3upKoi8mYB aST15Uig8j8qoUW1U217LL0jEHlSnHV3lcaDTXqDpTRR4Bfz9IqOgJgFZ8/oTfEo mSrjrLYef81Eyxr7ZIMQXEKKEK7V4UXKS0+/fDsiG/cXidhzt8UbTL9vqXqxM2+I DImyO+FAc/tkBG55LmzxPto1Nq0WbnZzRM/wTzrd0I/8NlevxtFbphg4evlHjFNI 7+GrqR87ViEwuAJJ9Je5QQjct5YJfFRWiZ5CMQIDAQABAoIBAGBi/GhEgezcHIg1 ltlHaFlLGuxsRbUnYwM9phVxnXk7GJlYe2/TjpERjPkIqOC6hBwwadZjJORP3FCc Mtc8PKRhjuZ377O7vU0915x2nnyLOGL1IE2AJ3iLi0ZFzTea0FPgg+5lWHM00s9F YI6qPcGtS41M+xtMWwZiYE3TBBRibHiY8ugGyaNAhiMKehyW05uApjlIF55wwCGx BkyESJpGRR/6853iHke6Ge+xVcMa9QmQdoH0QqL/8kT28PL568mJJr0Ow/83t4+d Pe70YPzKAxgUnaDsHJqO+b8qH69AEs8rTI5h2Mon6pH+bJT66KUoiXhn+Kf+4LSs henRP10CgYEA1QJSfuFOWVRjrg3N/rAIc/Ak84BTZavbyrkqBSuoTs9i/nMI/hOz VxpDntg7Bx2Tctl6sZO3GioTxKdc/YYaTKci1TKBbeginpsqEQVgwkMCy8HpvUmR fyAMqLwZC4h9+j+NiZtuoFJDTCgv+WYbasX+kWYEUM21bnSYuO7yEQsCgYEAyIdP r9uzqPgzN34Tmx+CNTa16VjhBh+zkBtXRLDLhWBeIYxoYNJARD98Pb1XZdvpkZZW Sk7MfaKo2/DomzyyyB/MbHWwAdFi3yb4y7uMJfyC1MzdUSNN3Vp579hJxHkJ+nN4 Ys76yfcEeVOLnvUT1Z0KKCdIWRdT1Lgi+X1itzMCgYBJUXlPzwGG4fNFj97d0X23 Wmt9nSgXkOYgi0eZbAOMzPmIF9R6kBFk49dur4Lx2g5Ms+r1gKC/0sfnIqxxX11i EQ1+UNoYGJUB/uql3TIG68XkmKR50P7RwRhaZBRC0gJ6xrFTMjsL2ATuC88niyvY vrn3FiRaI9RVZrDCxwxvLQKBgEXW4okEAqGBuAzGqztmkOnJoTehDdYdKmOxMgap cGiGdKJIjX3THDDoz3ONQyglnEZpTqpYoV3MTfU0BT8zt6x9bqwDnQY1D7NalmIW cqw0Mri8lQQSQKcsQLWo5aA466G/n5kCL1Qx5OwAjesRvhOyuvvbGpZ0ymyWqQ+t fLkDAoGATcul1L8y5D/wNVP1GXbXMZfBsFP3bbqy8c+Ashm6g8OLm2mGNntd5Z6h 1KkID7Yksh+dZ6t7XaPBtGACXX5Eryr537JVvdX8hAVCp5HVtaN/9VBVP8Ka2e4s VS/xeNgOMQ7uzhRPBJ8HiTmdI1nHhDnYQpGiBgQn0Z5RAkSvFMk=
-----END RSA PRIVATE KEY-----

# 2. 构造签名串

我们希望商户的技术开发人员按照当前文档约定的规则构造签名串。微信支付会使用同样的方式构造签名串。如果商户构造签名串的方式错误,将导致签名验证不通过。下面先说明签名串的具体格式。

签名串一共有五行,每一行为一个参数。结尾以\n(换行符,ASCII编码值为0x0A)结束,包括最后一行。如果参数本身以\n结束,也需要附加一个\n。

1HTTP请求方法\n
2URL\n
3请求时间戳\n
4请求随机串\n
5请求报文主体\n

以查询支付分订单接口为例:
第一步,获取HTTP请求的方法

1GET

第二步,获取请求的绝对URL(请注意需要去除域名部分)。拼接你的Query(查询参数),假设你的query参数如下

1limit=5
2offset=10
3authorized_data={"business_type":"FAVOR_STOCK", "stock_id":"2433405"}
4partner={"type":"APPID","appid":"wx4e1916a585d1f4e9","merchant_id":"2480029552"}

(1)先对authorized_data参数和partne参数做个URL encodeURL

1limit=5
2offset=10
3authorized_data%3D%7B%22business_type%22%3A%22FAVOR_STOCK%22%2C%20%22stock_id%22%3A%222433405%22%7D
4partner%3D%7B%22type%22%3A%22APPID%22%2C%22appid%22%3A%22wx4e1916a585d1f4e9%22%2C%22merchant_id%22%3A%222480029552%22%7D

(2)拼接你的请求URL,末尾加'?'和对应的查询字符串,多个字符串之间用&符号链接(请注意以下URL是在一行,因为排版原因可能看起来像换行,实际数据在一行)

1/v3/marketing/partnerships?limit=5&offset=10&authorized_data%3D%7B%22business_type%22%3A%22FAVOR_STOCK%22%2C%20%22stock_id%22%3A%222433405%22%7D&partner%3D%7B%22type%22%3A%22APPID%22%2C%22appid%22%3A%22wx4e1916a585d1f4e9%22%2C%22merchant_id%22%3A%222480029552%22%7D

第三步,获取发起请求时的系统当前时间戳,即格林威治时间1970年01月01日00时00分00秒(北京时间1970年01月01日08时00分00秒)起至现在的总秒数,作为请求时间戳。微信支付会拒绝处理很久之前发起的请求,请商户保持自身系统的时间准确。

1$ date +%s
21554208460

第四步,生成一个请求随机串,我们推荐生成随机数算法如下:调用随机数函数生成,将得到的值转换为字符串。这里,我们使用命令行直接生成一个。

1$ hexdump -n 16 -e '4/4 "%08X" 1 "\n"' /dev/random
2593BEC0C930BF1AFEB40B4A08C8FB242

第五步,获取请求中的请求报文主体(request body)。

对于委托营销-查询合作关系接口来说,请求报文主体是一个空串,只需要附加一个\n即可。

第六步,按照前述规则,构造的请求签名串如下:

1GET\n
2/v3/marketing/partnerships?limit=5&offset=10&authorized_data%3D%7B%22business_type%22%3A%22FAVOR_STOCK%22%2C%20%22stock_id%22%3A%222433405%22%7D&partner%3D%7B%22type%22%3A%22APPID%22%2C%22appid%22%3A%22wx4e1916a585d1f4e9%22%2C%22merchant_id%22%3A%222480029552%22%7D\n
31554208460\n
4593BEC0C930BF1AFEB40B4A08C8FB242\n
5\n

# 3. 计算签名值

绝大多数编程语言提供的签名函数支持对签名数据进行签名。强烈建议商户调用该类函数,使用商户私钥对待签名串进行SHA256 with RSA签名,并对签名结果进行Base64编码得到签名值。

1$ echo -n -e \
2'GET\n/v3/marketing/partnerships?limit=5&offset=10&authorized_data%3D%7B%22business_type%22%3A%22FAVOR_STOCK%22%2C%20%22stock_id%22%3A%222433405%22%7D&partner%3D%7B%22type%22%3A%22APPID%22%2C%22appid%22%3A%22wx4e1916a585d1f4e9%22%2C%22merchant_id%22%3A%222480029552%22%7D\n1554208460\n593BEC0C930BF1AFEB40B4A08C8FB242\n\n' \
3 | openssl dgst -sha256 -sign apiclient_test_key.pem \
4 | openssl base64 -A

得出的签名值如下,你可以用一些校验工具校验你通过命令行或者你的代码得到的签名值是否和以下值一样,一样则表示计算过程无误,如果不一致则请检查签名的参数是否一致、签名串是否有严格换行等

1C9PrZx8RTw7NF+e6SLmZxKgUBdXjH6EmUiu1i85Y6MApfWn4ueNpS4ED5no6uGObU0cfzTdaWyl6gAWDmyO2nG3MjHursadpzpNT8d+HaZapKis+boTHwJLgZXHXtacjX4zx2lOk/AONrKCLkjXRnh/DDp/kNsmDNYEiu+d/SeVvr+cL0XkL0CibAphyQSLYkv7Fh9uel89ax3ZGgVnBx+/MaBLCrYc1UqyYBDqfWPhS9fZf2OSghWMFp9c5dm+ORc97XbgzSOwAl8dcfLSrL/Sb4+L57+JZiq0iURjMXWzAD8FTUFYsJtJOYszRXJKLZNh4WGST39oplhhSdtxcoQ==

# 4. 设置HTTP头

微信支付商户API v3要求请求通过HTTP Authorization头来传递签名。Authorization由认证类型和签名信息两个部分组成。

下面我们使用命令行演示如何生成签名。

1Authorization: 认证类型 签名信息

具体组成为:

  1. 认证类型,目前为WECHATPAY2-SHA256-RSA2048

  2. 签名信息

    • 发起请求的商户(包括直连商户、服务商或渠道商)的商户号mchid
    • 商户API证书序列号serial_no,用于声明所使用的证书,注意这里是商户API证书而不是平台证书,请勿混用,如果不知道如何查看API证书序列号,可参考文档文末的常见问题。
    • 请求随机串nonce_str,和你上面构造签名串的随机串要保持一致
    • 时间戳timestamp,和你上面构造签名串的时间戳要保持一致
    • 签名值signature,上面算出来的签名值

提示

注意:以上五项签名信息,无顺序要求。

Authorization头的示例如下:(注意,示例因为排版可能存在换行,实际数据应在一行)

1Authorization: WECHATPAY2-SHA256-RSA2048 mchid="1900007291",nonce_str="593BEC0C930BF1AFEB40B4A08C8FB242",signature="C9PrZx8RTw7NF+e6SLmZxKgUBdXjH6EmUiu1i85Y6MApfWn4ueNpS4ED5no6uGObU0cfzTdaWyl6gAWDmyO2nG3MjHursadpzpNT8d+HaZapKis+boTHwJLgZXHXtacjX4zx2lOk/AONrKCLkjXRnh/DDp/kNsmDNYEiu+d/SeVvr+cL0XkL0CibAphyQSLYkv7Fh9uel89ax3ZGgVnBx+/MaBLCrYc1UqyYBDqfWPhS9fZf2OSghWMFp9c5dm+ORc97XbgzSOwAl8dcfLSrL/Sb4+L57+JZiq0iURjMXWzAD8FTUFYsJtJOYszRXJKLZNh4WGST39oplhhSdtxcoQ==",timestamp="1554208460",serial_no="408B07E79B8269FEC3D5D3E6AB8ED163A6A380DB"

最终我们可以组一个包含了签名的HTTP请求了。请注意这里因为HTTPS请求里面带有&字符,因此需要加上双引号

1$curl -X GET \
2"https://api.mch.weixin.qq.com/v3/marketing/partnerships?limit=5&offset=10&authorized_data%3D%7B%22business_type%22%3A%22FAVOR_STOCK%22%2C%20%22stock_id%22%3A%222433405%22%7D&partner%3D%7B%22type%22%3A%22APPID%22%2C%22appid%22%3A%22wx4e1916a585d1f4e9%22%2C%22merchant_id%22%3A%222480029552%22%7D" \
3-H 'Authorization: WECHATPAY2-SHA256-RSA2048 mchid="1900007291",nonce_str="593BEC0C930BF1AFEB40B4A08C8FB242",signature="C9PrZx8RTw7NF+e6SLmZxKgUBdXjH6EmUiu1i85Y6MApfWn4ueNpS4ED5no6uGObU0cfzTdaWyl6gAWDmyO2nG3MjHursadpzpNT8d+HaZapKis+boTHwJLgZXHXtacjX4zx2lOk/AONrKCLkjXRnh/DDp/kNsmDNYEiu+d/SeVvr+cL0XkL0CibAphyQSLYkv7Fh9uel89ax3ZGgVnBx+/MaBLCrYc1UqyYBDqfWPhS9fZf2OSghWMFp9c5dm+ORc97XbgzSOwAl8dcfLSrL/Sb4+L57+JZiq0iURjMXWzAD8FTUFYsJtJOYszRXJKLZNh4WGST39oplhhSdtxcoQ==",timestamp="1554208460",serial_no="408B07E79B8269FEC3D5D3E6AB8ED163A6A380DB"' \
4-H 'Accept: application/json'

# 5、常见问题请参考

签名验证常见问题

反馈
咨询
目录