Query模式接口签名
这里以RSA签名为例,国密更换对应的加密方式即可
1、怎么判断当前请求的API是否属于请求参数里带Query参数?
你可以点击查看一个API接口说明文档,可以看到该接口请求参数部分参数类型为Query参数,不同的参数类型构造请求签名略有不同,Query参数对应的是Http GET请求方式,将参数拼接在URL里发送请求.
为了方便大家理解,我们将使用一对测试的公私钥,通过命令行形式演示接口调用签名过程,一步一步介绍请求参数里带Query参数(查询参数),如何计算签名。强烈建议你使用测试的公私钥,按照本文实际操作一下,如果算出来的签名和文档的一致则说明计算无误。实际业务中请替换为你的真实的参数。
假设你的qurey参数如下所示,我们将一步步演示如何计算签名
page_size=100
page_index=50
query_params={"mch_id":"10283021","order_id":"120948901284"}
2. 如何构造请求签名
2.1. 获取商户API证书
此处我们已经拿到了商户API证书,并且将对应的商户API私钥api_key.pem,保存在了本地
商户号:10283021
证书序列号:139248429
宝付证书序列号: 138924182
API证书私钥:你需要将以下文件保存为pem格式,为了避免大家和自己的真实的公私钥混淆,此处将其保存为了api_test_key.pem
-----BEGIN PRIVATE KEY-----
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCm2mb6q8gMKH/3
CNTbpJAIrbqiBiQGEOtjGcBrDYltsGynWgNscqT7WvfzU14FQbYcQUC5T4Wvva7m
i3fIp3OgX8VqMDNA0qebnr38Pe6kqiLyZgFpJPXlSKDyPyqhRbVTbXssvSMQeVKc
dXeVxoNNeoOlNFHgF/P0io6AmAVnz+hN8SiZKuOsth5/zUTLGvtkgxBcQooQrtXh
RcpLT798OyIb9xeJ2HO3xRtMv2+perEzb4gMibI74UBz+2QEbnkubPE+2jU2rRZu
dnNEz/BPOt3Qj/w2V6/G0VumGDh6+UeMU0jv4aupHztWITC4Akn0l7lBCNy3lgl8
VFaJnkIxAgMBAAECggEAYGL8aESB7NwciDWW2UdoWUsa7GxFtSdjAz2mFXGdeTsY
mVh7b9OOkRGM+Qio4LqEHDBp1mMk5E/cUJwy1zw8pGGO5nfvs7u9TT3XnHaefIs4
YvUgTYAneIuLRkXNN5rQU+CD7mVYczTSz0Vgjqo9wa1LjUz7G0xbBmJgTdMEFGJs
eJjy6AbJo0CGIwp6HJbTm4CmOUgXnnDAIbEGTIRImkZFH/rzneIeR7oZ77FVwxr1
CZB2gfRCov/yRPbw8vnryYkmvQ7D/ze3j5097vRg/MoDGBSdoOwcmo75vyofr0AS
zytMjmHYyifqkf5slPropSiJeGf4p/7gtKyF6dE/XQKBgQDVAlJ+4U5ZVGOuDc3+
sAhz8CTzgFNlq9vKuSoFK6hOz2L+cwj+E7NXGkOe2DsHHZNy2Xqxk7caKhPEp1z9
hhpMpyLVMoFt6CKemyoRBWDCQwLLwem9SZF/IAyovBkLiH36P42Jm26gUkNMKC/5
Zhtqxf6RZgRQzbVudJi47vIRCwKBgQDIh0+v27Oo+DM3fhObH4I1NrXpWOEGH7OQ
G1dEsMuFYF4hjGhg0kBEP3w9vVdl2+mRllZKTsx9oqjb8OibPLLIH8xsdbAB0WLf
JvjLu4wl/ILUzN1RI03dWnnv2EnEeQn6c3hizvrJ9wR5U4ue9RPVnQooJ0hZF1PU
uCL5fWK3MwKBgElReU/PAYbh80WP3t3Rfbdaa32dKBeQ5iCLR5lsA4zM+YgX1HqQ
EWTj126vgvHaDkyz6vWAoL/Sx+cirHFfXWIRDX5Q2hgYlQH+6qXdMgbrxeSYpHnQ
/tHBGFpkFELSAnrGsVMyOwvYBO4LzyeLK9i+ufcWJFoj1FVmsMLHDG8tAoGARdbi
iQQCoYG4DMarO2aQ6cmhN6EN1h0qY7EyBqlwaIZ0okiNfdMcMOjPc41DKCWcRmlO
qlihXcxN9TQFPzO3rH1urAOdBjUPs1qWYhZyrDQyuLyVBBJApyxAtajloDjrob+f
mQIvVDHk7ACN6xG+E7K6+9salnTKbJapD618uQMCgYBNy6XUvzLkP/A1U/UZdtcx
l8GwU/dturLxz4CyGbqDw4ubaYY2e13lnqHUqQgPtiSyH51nq3tdo8G0YAJdfkSv
KvnfslW91fyEBUKnkdW1o3/1UFU/wprZ7ixVL/F42A4xDu7OFE8EnweJOZ0jWceE
OdhCkaIGBCfRnlECRK8UyQ==
-----END PRIVATE KEY-----
2.2. 构造签名串
签名串一共有六行,每一行为一个参数。结尾以\n(换行符,ASCII编码值为0x0A)结束,包括最后一行。如果参数本身以\n结束,也需要附加一个\n。
HTTP请求方法\n
URL\n
请求时间戳\n
请求随机串\n
数字信封\n
请求报文主体\n
第一步,获取HTTP请求的方法
GET
第二步,获取请求的绝对URL(请注意需要去除域名部分)。拼接你的Query(查询参数),假设你的query参数如下
page_size=100
page_index=50
query_params={"mch_id":"10283021","order_id":"120948901284"}
(1)先对 query_params 参数做URL encode
page_size=100
page_index=50
query_params=%7B%22mch_id%22%3A%2210283021%22%2C%22order_id%22%3A%22120948901284%22%7D
(2)拼接你的请求URL,查询参数需要在末尾加’?’和对应的查询字符串,多个字符串之间用&符号链接(请注意以下URL是在一行,因为排版原因可能看起来像换行,实际数据在一行)
假设完整请求URL为: https://api.baofu.com/v4/test/pagequery
先获取请求URL(去除域名部分) /v4/test/pagequery
再拼接完整的query参数,结果如下:
/v4/test/pagequery?page_size=100&page_index=50&query_params=%7B%22mch_id%22%3A%2210283021%22%2C%22order_id%22%3A%22120948901284%22%7D
第三步,获取发起请求时的系统当前时间戳,即格林威治时间1970年01月01日00时00分00秒(北京时间1970年01月01日08时00分00秒)起至现在的总秒数,作为请求时间戳。宝付会拒绝处理很久之前发起的请求,请商户保持自身系统的时间准确。
$ date +%s
1760067876
第四步,生成一个请求随机串,这里,我们使用命令行直接生成一个。
$ openssl rand -hex 16 | tr -d '\n' | tr 'a-f' 'A-F'
5FC2FC21E871BD5B8C7A3E0B0339BC8F
第五步,生成数字信封。
当前接口为查询接口,无敏感信息,只需要附加一个\n即可
第六步,获取请求中的请求报文主体(request body)。
对于Query接口来说,请求报文主体是一个空串,只需要附加一个\n即可。
第七步,按照前述规则,构造的请求签名串如下:
GET\n
/v4/test/pagequery?page_size=100&page_index=50&query_params=%7B%22mch_id%22%3A%2210283021%22%2C%22order_id%22%3A%22120948901284%22%7D\n
1760067876\n
5FC2FC21E871BD5B8C7A3E0B0339BC8F\n
\n
\n
2.3. 计算签名值
绝大多数编程语言提供的签名函数支持对签名数据进行签名。强烈建议商户调用该类函数,使用商户私钥对待签名串进行SHA256 with RSA签名,并对签名结果进行16进制编码转大写得到签名值。
$ echo -n -e \
'GET\n/v4/test/pagequery?page_size=100&page_index=50&query_params=%7B%22mch_id%22%3A%2210283021%22%2C%22order_id%22%3A%22120948901284%22%7D\n1760067876\n5FC2FC21E871BD5B8C7A3E0B0339BC8F\n\n\n' \
| openssl dgst -sha256 -sign api_test_key.pem \
| xxd -p | tr -d '\n' | tr 'a-f' 'A-F'
得出的签名值如下,你可以用一些校验工具校验你通过命令行或者你的代码得到的签名值是否和以下值一样,一样则表示计算过程无误,如果不一致则请检查签名的参数是否一致、签名串是否有严格换行等
1C4165ECD62B0101C2E114625110B5433B3BC24E08CB0390482B4D007C09667EFDDA26F05E9ED3E05AE3159BA1240790AA33AFB27661BC308CEE86249A5D16A31011CDC81758A07584DAF371E13FF83E921C348DC4466920E2ECE2F47A6A82BA36F607FDA3B2AFCCB3C1EF8B7EEBEE27630460793FEE143E5202D5B4852B310F88CCB0F7D8999434E18197FD7CE50554C9A2762DF11A478AF9F1663C9F5B3023A69CE2E33F2A126793C464161ED761FEBE05B74C5DD8FBD5719FBD9711A5CD767F1E2953F3E99395ADB0985C6B69E87333EFA2214F79B172E5E97A1DB2DF405FC5ECE479C00B928452E1E62DE0AC83D553CBBFD9ED8E081EB372B3172670FC9B
2.4. 设置HTTP头
宝付要求请求通过HTTP Authorization头来传递签名。Authorization由认证类型和签名信息两个部分组成。
Authorization: 认证类型 签名信息
具体组成为:
- 认证类型,取值 RSA/SM2
签名信息
| 参数名 | 说明 |
|---|---|
| mch_id | 宝付分配的唯一商编 |
| app_id | 宝付终端号,选填,若传值,则使用宝付4.0证书 |
| nonce_str | 请求随机串,和上面构造签名串的随机串要保持一致 |
| timestamp | 时间戳 和上面构造签名串的时间戳要保持一致 |
| serial_no | 商户API证书序列号,用于声明所使用的证书 |
| baofu_serial_no | 宝付证书序列号, 联系技术支持提供 |
| dgtl_envlp | 数字信封(非必填),16位密钥,用宝付公钥加密后传输 |
| signature | 签名值,上面算出来的签名值 |
注意:以上七项签名信息,无顺序要求。数字信封参数可以为空
根据示例最终生成的Authrization头如下:
Authorization: RSA mch_id="10283021",app_id="120838",nonce_str="5FC2FC21E871BD5B8C7A3E0B0339BC8F",signature="1C4165ECD62B0101C2E114625110B5433B3BC24E08CB0390482B4D007C09667EFDDA26F05E9ED3E05AE3159BA1240790AA33AFB27661BC308CEE86249A5D16A31011CDC81758A07584DAF371E13FF83E921C348DC4466920E2ECE2F47A6A82BA36F607FDA3B2AFCCB3C1EF8B7EEBEE27630460793FEE143E5202D5B4852B310F88CCB0F7D8999434E18197FD7CE50554C9A2762DF11A478AF9F1663C9F5B3023A69CE2E33F2A126793C464161ED761FEBE05B74C5DD8FBD5719FBD9711A5CD767F1E2953F3E99395ADB0985C6B69E87333EFA2214F79B172E5E97A1DB2DF405FC5ECE479C00B928452E1E62DE0AC83D553CBBFD9ED8E081EB372B3172670FC9B",timestamp="1760067876",serial_no="139248429",baofu_serial_no="138924182"
最终我们可以组一个包含了签名的HTTP请求了。请注意这里因为HTTPS请求里面带有&字符,因此需要加上双引号
$ curl -X GET \
https://api.baofu.com/v4/test/pagequery?page_size=100&page_index=50&query_params=%7B%22mch_id%22%3A%2210283021%22%2C%22order_id%22%3A%22120948901284%22%7D \
-H 'Authorization: RSA mch_id="10283021",nonce_str="5FC2FC21E871BD5B8C7A3E0B0339BC8F",signature="1C4165ECD62B0101C2E114625110B5433B3BC24E08CB0390482B4D007C09667EFDDA26F05E9ED3E05AE3159BA1240790AA33AFB27661BC308CEE86249A5D16A31011CDC81758A07584DAF371E13FF83E921C348DC4466920E2ECE2F47A6A82BA36F607FDA3B2AFCCB3C1EF8B7EEBEE27630460793FEE143E5202D5B4852B310F88CCB0F7D8999434E18197FD7CE50554C9A2762DF11A478AF9F1663C9F5B3023A69CE2E33F2A126793C464161ED761FEBE05B74C5DD8FBD5719FBD9711A5CD767F1E2953F3E99395ADB0985C6B69E87333EFA2214F79B172E5E97A1DB2DF405FC5ECE479C00B928452E1E62DE0AC83D553CBBFD9ED8E081EB372B3172670FC9B",timestamp="1760067876",serial_no="139248429",baofu_serial_no="138924182" \
-H 'Accept: application/json'