请求参数里带Body参数(包体参数),如何计算签名
更新时间:2024.08.22为了方便大家理解,我们将使用测试的一对公私钥,通过命令行形式调用"JSAPI下单接口 (opens new window)",一步一步介绍如何请求参数里带Body参数(包体参数),如何计算签名。强烈建议你使用测试的公私钥,按照本文实操作一下,如果算出来的签名和文档的一致则说明计算无误。实际业务中请替换为你的真实的参数。
# 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. 构造签名串
我们希望商户的技术开发人员按照当前文档约定的规则构造签名串。微信支付会使用同样的方式构造签名串。如果商户构造签名串的方式错误,将导致签名验证不通过。下面先说明签名串的具体格式。
签名串一共有5个部分,每一行为一个参数。结尾以\n(换行符,ASCII编码值为0x0A)结束,包括最后一行。如果参数本身以\n结束,也需要附加一个\n。
1HTTP请求方法\n2URL\n3请求时间戳\n4请求随机串\n5请求报文主体\n
以JSAPI下单接口为例,
第一步,获取HTTP请求的方法
1POST
第二步,获取请求的绝对URL,请注意需要去除域名部分。
1/v3/pay/transactions/jsapi
第三步,获取发起请求时的系统当前时间戳,即格林威治时间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)。
你可以将所有参数放在一行,对应的发起签名请求的时候body参数也应该放在一行。
你也可以将参数以多行计算签名,对应发起请求的时候body参数也要是多行。即你计算签名时body是怎么样的,你发起请求时body就应该是怎么样的。
这里以将所有参数放到一行做演示,如果你想了解将参数放在多行可以参考文末说明
1{"appid":"wxd678efh567hg6787","mchid":"1230000109","description":"Image形象店-深圳腾大-QQ公仔","out_trade_no":"1217752501201407033233368018","notify_url":"https://www.weixin.qq.com/wxpay/pay.php","amount":{"total":100,"currency":"CNY"},"payer":{"openid":"oUpF8uMuAJO_M2pxb1Q9zNjWeS6o"}}
第六步,按照前述规则,构造的请求签名串如下:
1POST\n 2/v3/pay/transactions/jsapi\n 31554208460\n 4593BEC0C930BF1AFEB40B4A08C8FB242\n 5{"appid":"wxd678efh567hg6787","mchid":"1230000109","description":"Image形象店-深圳腾大-QQ公仔","out_trade_no":"1217752501201407033233368018","notify_url":"https://www.weixin.qq.com/wxpay/pay.php","amount":{"total":100,"currency":"CNY"},"payer":{"openid":"oUpF8uMuAJO_M2pxb1Q9zNjWeS6o"}}\n
# 3. 计算签名值
绝大多数编程语言提供的签名函数支持对签名数据进行签名。强烈建议商户调用该类函数,使用商户私钥对待签名串进行SHA256 with RSA签名,并对签名结果进行Base64编码得到签名值。
请注意处理单双引号转义问题,第二行的外层是单引号,则里面的参数不需要转义,如果第二行最外层使用了双引号,则body参数的双引号都需要转义
1$ echo -n -e \2 'POST\n/v3/pay/transactions/jsapi\n1554208460\n593BEC0C930BF1AFEB40B4A08C8FB242\n{"appid":"wxd678efh567hg6787","mchid":"1230000109","description":"Image形象店-深圳腾大-QQ公仔","out_trade_no":"1217752501201407033233368018","notify_url":"https://www.weixin.qq.com/wxpay/pay.php","amount":{"total":100,"currency":"CNY"},"payer":{"openid":"oUpF8uMuAJO_M2pxb1Q9zNjWeS6o"}}\n' \3 | openssl dgst -sha256 -sign apiclient_test_key.pem \4 | openssl base64 -A
得出的签名值如下,你可以用一些校验工具校验你通过命令行或者你的代码得到的签名值是否和以下值一样,一样则表示计算过程无误,如果不一致则请检查签名的参数是否一致、签名串是否有严格换行等
1gEuexJ547PHFV77TQ6eiE4tphVYfWfUe1Wc2dBmVnoMYU2rl/M4zhw+b3vBhuMw6AC7pteNkryLA7UWU2h+umo0OdSuuLm1++O3NckQPCSfm6dypsjn4GYm84KMqXWFrhFmyxEwIdEJDr3w1UYfxOcu55OQupfLkrt/ZzuOspnliJFrPzGQFUk7lGqMMtpz3EfbDUNxnVsHblORg3hVmuYNmbGWnS2ovU30Y2Q+iKFDxzkaXBk8LTy6HzvxizRo6Q+J4SVM7O0hKXfgo1QdI68kpzNULb3EVBXlhTyPUzhkHzzLxECL1qHl3HH2hEv8++C+4wBlsagF3j/O6PABojA==
# 4. 设置HTTP头
微信支付商户API v3要求请求通过HTTP Authorization头来传递签名。Authorization由认证类型和签名信息两个部分组成。
下面我们使用命令行演示如何生成签名。
1Authorization: 认证类型 签名信息
具体组成为:
认证类型,目前为WECHATPAY2-SHA256-RSA2048
签名信息
- 发起请求的商户(包括直连商户、服务商或渠道商)的商户号mchid
- 商户API证书序列号serial_no,用于声明所使用的证书,注意这里是商户API证书而不是平台证书,请勿混用,如果不知道如何查看API证书序列号,可参考文档文末的常见问题。
- 请求随机串nonce_str,和你上面构造签名串的随机串要保持一致
- 时间戳timestamp,和你上面构造签名串的时间戳要保持一致
- 签名值signature,上面算出来的签名值
提示
注意:以上五项签名信息,无顺序要求。
Authorization头的示例如下:(注意,示例因为排版可能存在换行,实际数据应在一行)
1Authorization: WECHATPAY2-SHA256-RSA2048 mchid="1900007291",nonce_str="593BEC0C930BF1AFEB40B4A08C8FB242",signature="gEuexJ547PHFV77TQ6eiE4tphVYfWfUe1Wc2dBmVnoMYU2rl/M4zhw+b3vBhuMw6AC7pteNkryLA7UWU2h+umo0OdSuuLm1++O3NckQPCSfm6dypsjn4GYm84KMqXWFrhFmyxEwIdEJDr3w1UYfxOcu55OQupfLkrt/ZzuOspnliJFrPzGQFUk7lGqMMtpz3EfbDUNxnVsHblORg3hVmuYNmbGWnS2ovU30Y2Q+iKFDxzkaXBk8LTy6HzvxizRo6Q+J4SVM7O0hKXfgo1QdI68kpzNULb3EVBXlhTyPUzhkHzzLxECL1qHl3HH2hEv8++C+4wBlsagF3j/O6PABojA==",timestamp="1554208460",serial_no="408B07E79B8269FEC3D5D3E6AB8ED163A6A380DB"
最终我们可以组一个包含了签名的HTTP请求了。
(1)请注意第六行的body参数必须在一行,不能换行,因为签名计算签名时body就是以一行来计算签名的,这里发起请求时需要和签名时的保持一致
(2)请注意Authorization的timestamp="1554208460",serial_no="408B07E79B8269FEC3D5D3E6AB8ED163A6A380DB"必须和你计算签名是传入的值是一致的
(3)此处只是一个示例,用于大家参考计算的格式,由于示例密钥本身是不可用的,因此以下请求并不真正可用
1curl -X POST \2 https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi \3 -H 'Authorization: WECHATPAY2-SHA256-RSA2048 mchid="1900007291",nonce_str="593BEC0C930BF1AFEB40B4A08C8FB242",signature="gEuexJ547PHFV77TQ6eiE4tphVYfWfUe1Wc2dBmVnoMYU2rl/M4zhw+b3vBhuMw6AC7pteNkryLA7UWU2h+umo0OdSuuLm1++O3NckQPCSfm6dypsjn4GYm84KMqXWFrhFmyxEwIdEJDr3w1UYfxOcu55OQupfLkrt/ZzuOspnliJFrPzGQFUk7lGqMMtpz3EfbDUNxnVsHblORg3hVmuYNmbGWnS2ovU30Y2Q+iKFDxzkaXBk8LTy6HzvxizRo6Q+J4SVM7O0hKXfgo1QdI68kpzNULb3EVBXlhTyPUzhkHzzLxECL1qHl3HH2hEv8++C+4wBlsagF3j/O6PABojA==",timestamp="1554208460",serial_no="408B07E79B8269FEC3D5D3E6AB8ED163A6A380DB"' \4 -H 'Accept: application/json' \5 -H 'Content-Type: application/json' \6 -d '{"appid":"wxd678efh567hg6787","mchid":"1230000109","description":"Image形象店-深圳腾大-QQ公仔","out_trade_no":"1217752501201407033233368018","notify_url":"https://www.weixin.qq.com/wxpay/pay.php","amount":{"total":100,"currency":"CNY"},"payer":{"openid":"oUpF8uMuAJO_M2pxb1Q9zNjWeS6o"}}'
# 5、常见问题请参考
# (1)签名验签常见问题详见签名验证常见问题
# (2)以下演示body有多个参数时,如何以多行来计算签名并且发起请求
# 1.构造签名串
依然以JSAPI下单接口为例,前四步保持不变,
第五步,获取请求中的请求报文主体(request body)。
将参数以多行计算签名,对应发起请求的时候body参数也要是多行。即你计算签名时body是怎么样的,你发起请求时body就应该是怎么样的。
1{2"appid":"wxd678efh567hg6787",3"mchid":"1230000109",4"description":"Image形象店-深圳腾大-QQ公仔",5"out_trade_no":"1217752501201407033233368018",6"notify_url":"https://www.weixin.qq.com/wxpay/pay.php",7"amount":{"total":100,"currency":"CNY"},8"payer":{"openid":"oUpF8uMuAJO_M2pxb1Q9zNjWeS6o"}9}
第六步,按照前述规则,构造的请求签名串如下,每一行的结尾以\n(换行符,ASCII编码值为0x0A)结束,包括最后一行。如果参数本身以\n结束,也需要附加一个\n
1POST\n 2/v3/pay/transactions/jsapi\n 31554208460\n 4593BEC0C930BF1AFEB40B4A08C8FB242\n 5{\n 6"appid":"wxd678efh567hg6787",\n 7"mchid":"1230000109",\n 8"description":"Image形象店-深圳腾大-QQ公仔",\n 9"out_trade_no":"1217752501201407033233368018",\n 10"notify_url":"https://www.weixin.qq.com/wxpay/pay.php",\n 11"amount":{"total":100,"currency":"CNY"},\n 12"payer":{"openid":"oUpF8uMuAJO_M2pxb1Q9zNjWeS6o"}\n 13}\n
# 2.计算签名值
绝大多数编程语言提供的签名函数支持对签名数据进行签名。强烈建议商户调用该类函数,使用商户私钥对待签名串进行SHA256 with RSA签名,并对签名结果进行Base64编码得到签名值。
请注意处理单双引号转义问题,第二行的外层是单引号,则里面的参数不需要转义,如果第二行最外层使用了双引号,则body参数的双引号都需要转义
1$ echo -n -e \2'POST\n/v3/pay/transactions/jsapi\n1554208460\n593BEC0C930BF1AFEB40B4A08C8FB242\n{\n"appid":"wxd678efh567hg6787",\n"mchid":"1230000109",\n"description":"Image形象店-深圳腾大-QQ公仔",\n"out_trade_no":"1217752501201407033233368018",\n"notify_url":"https://www.weixin.qq.com/wxpay/pay.php",\n"amount":{"total":100,"currency":"CNY"},\n"payer":{"openid":"oUpF8uMuAJO_M2pxb1Q9zNjWeS6o"}\n}\n' \3 | openssl dgst -sha256 -sign apiclient_test_key.pem \4 | openssl base64 -A
得出的签名值如下,你可以用一些校验工具校验你通过命令行或者你的代码得到的签名值是否和以下值一样,一样则表示计算过程无误,如果不一致则请检查签名的参数是否一致、签名串是否有严格换行等
1E7pP5rphKguQ29ql13Vxt2+lumoZxvV44SU5vTij9YeK6qdf9/iIKVGCH+XjZZl/ov2HS0BGHmXFzrP7IwLMknPWlmB8MHnTHz4vUpONUGcOboN++SDTaFLp+wbFOzp+qH3bFGpjJc5MRpUCpuGobVfP2/hXICyYOfkd/xtdCdFUwdkJI8cuGgLJvOw36X3y+6WIz1sTfrTrioNswbTot12h3zEI7waLVlneJ0V93zHAIyCD3RX36iee6wnA2bI1xYgGDM7AgEWuqAHx5lljo0uD7UyxnkJIoqfFrwLeR5Fg0PnAM9Ue0vlAfMgIkMmJjNdMo6PmiXcjRmuEky6f7g==
# 3.设置HTTP头
1Authorization: WECHATPAY2-SHA256-RSA2048 mchid="1900007291",nonce_str="593BEC0C930BF1AFEB40B4A08C8FB242",signature="E7pP5rphKguQ29ql13Vxt2+lumoZxvV44SU5vTij9YeK6qdf9/iIKVGCH+XjZZl/ov2HS0BGHmXFzrP7IwLMknPWlmB8MHnTHz4vUpONUGcOboN++SDTaFLp+wbFOzp+qH3bFGpjJc5MRpUCpuGobVfP2/hXICyYOfkd/xtdCdFUwdkJI8cuGgLJvOw36X3y+6WIz1sTfrTrioNswbTot12h3zEI7waLVlneJ0V93zHAIyCD3RX36iee6wnA2bI1xYgGDM7AgEWuqAHx5lljo0uD7UyxnkJIoqfFrwLeR5Fg0PnAM9Ue0vlAfMgIkMmJjNdMo6PmiXcjRmuEky6f7g==",timestamp="1554208460",serial_no="408B07E79B8269FEC3D5D3E6AB8ED163A6A380DB"
# 4.发起请求
再次说明你计算签名时body是怎么样的,你发起请求时body就应该是怎么样的,因为这里计算签名时body是多行的,发起请求时body也应该是严格一致的
1curl -X POST \2 https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi \3 -H 'Authorization: WECHATPAY2-SHA256-RSA2048 mchid="1900007291",nonce_str="593BEC0C930BF1AFEB40B4A08C8FB242",signature="gEuexJ547PHFV77TQ6eiE4tphVYfWfUe1Wc2dBmVnoMYU2rl/M4zhw+b3vBhuMw6AC7pteNkryLA7UWU2h+umo0OdSuuLm1++O3NckQPCSfm6dypsjn4GYm84KMqXWFrhFmyxEwIdEJDr3w1UYfxOcu55OQupfLkrt/ZzuOspnliJFrPzGQFUk7lGqMMtpz3EfbDUNxnVsHblORg3hVmuYNmbGWnS2ovU30Y2Q+iKFDxzkaXBk8LTy6HzvxizRo6Q+J4SVM7O0hKXfgo1QdI68kpzNULb3EVBXlhTyPUzhkHzzLxECL1qHl3HH2hEv8++C+4wBlsagF3j/O6PABojA==",timestamp="1554208460",serial_no="408B07E79B8269FEC3D5D3E6AB8ED163A6A380DB"' \4 -H 'Accept: application/json' \5 -H 'Content-Type: application/json' \6 -d '{7"appid":"wxd678efh567hg6787",8"mchid":"1230000109",9"description":"Image形象店-深圳腾大-QQ公仔",10"out_trade_no":"1217752501201407033233368018",11"notify_url":"https://www.weixin.qq.com/wxpay/pay.php",12"amount":{"total":100,"currency":"CNY"},13"payer":{"openid":"oUpF8uMuAJO_M2pxb1Q9zNjWeS6o"}14}'