图片上传接口,如何计算签名

更新时间:2025.09.22

图片上传类的接口构造请求签名方式有别与其他类型接口,为了方便大家理解,我们将使用测试的一对品牌API证书公私钥,通过命令行形式调用图片上传接口,一步一步介绍如何计算签名。强烈建议你使用测试的公私钥,按照本文实际操作一下,如果算出来的签名和文档的一致则说明计算无误。实际业务中请替换为你的真实的参数。

1. 获取品牌API证书

构造请求签名需要使用品牌API证书,可以参考什么是品牌API证书?如何获取品牌API证书?

此处我们已经拿到了品牌API证书,并且将对应的品牌API证书私钥apiclient_key.pem,保存在了本地

品牌ID:100XX

证书序列号:3493DE0D9BB4EB98A8C65EAA7E8EE887EC24B71A

品牌API证书私钥:你需要将以下文件保存为pem格式,为了避免大家和自己的真实的公私钥混淆,此处将其保存为了apiclient_test_key.pem

1-----BEGIN PRIVATE KEY-----
2MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCv0rFCsNi1Sbdn
3HtEtdxDdgQZ5zI1PZL89jsI0NSw8kQ77HwCJpFfPT6PhLYVCXaNJVynBcvOJzPn4
43LmhNLGN+Uro4s/7wvDIU3NqunVC1V4I0NL3TsUMMMIakgZu8n0vM/ukhzYzraFO
5yY+T0kMXL2fatEUU4rvtcUCeoNDVP7r0c2WTPk0vXayx1tpnN7cXdbbjoAkzMBcV
6zjMqbhcT4o87kSRbdltKGpiMOJ6NqJgUaQ6ZfC7x0u7tBpZlqEnD464Hgo0UPWiB
7EdoKqS4WidGclEIha44G/iPhCwXW0c1Sae4QCvN+16F/XmYuemHp2HQ9vjrAPeKS
82Up/5RFTAgMBAAECggEAB9TDjmvgCxsQbyhhOrwt5R/FERG6TYn4Np6wKbEgmkX/
9u9GirX7DZnlunC3x3IXdKvwV4QbksAOQMrRqFDMLoX40BvFrQBRrsxB8eIl7hZGJ
10Ua0zaE562lMlohdU8AYe60ZOdAKNuHmIUMELgxL/Z/31izkyRn7ezfGYZjhVdNoB
117H8oJfXe1wuznnmlq4eguRjQpLP3+BrM9UkvyUZiNzTcaAnDSz0zWRAMdamGL3+L
12qUFmS7FOp2C0PJGke3p5A5S7DGW7EGS8IFerMuXe/xOE6/nhZ3LNFJP0nVMfMLs8
13TVN538I7l1B4Q9J956zIZU8KOzpeqM82eCjhIW70SQKBgQDVBh6JjIPX3S63CKwm
14hciuAaL8V/Pz1MOSX6Z0DDhR9FS9OZKAhFUb6gPcYFPTIKmln8/8eQxwflhbgWiq
15ioERrDuLmyF82Fi/5zzosqa1aY24wRYax2j4aAFZVytirdX/4UEMmbMDMjQcQjqo
16Tb9TcOvSKlrfM4eiTNe97EYmRwKBgQDTS0mqM6E3wxhcsbz5w1N5oU8GL7UlPIDy
17gYWUoU78JdycKwYnN3hfAy2qvogblS/IYFVnoJpWHTyxTXVPpkX1gdZcQL0PzeEv
186rXZWgVJfz9GxPiNJNhakJnvWTj1synXvdR+mjQ2rO3tk+XCxkW0vvWedNv07Ge7
195ksa42vmlQKBgQCMRCA9b+GsdL561OIN54+RTBCW2g8PIay5J/RBe35mMFzP0CXw
20K7Ki079BD8iCP4KVRRq9YrNXK0pgzmAt009TZLY8oaQ2QXqGues4SdJNp7gizDkS
213vT2g/1HZ4dwzYgYmaisdFQUKa14Yf+frLnrZnJRC4SUbajErJZuPzKdpwKBgG8Y
22FMFSqB+DipmiMjQ4SPmYoM4l416Ss1HOXAfL0JWu6pGJ5ZBVEAsUxrwRtcqa5Ca8
23z+rOfJdug+zNRzL7v6jX/Xc/6qgWnaHuDHMda847A3AYPH8psj/b67P2+4XkD8oJ
24W2K9fVqKDgduTc3dJeVkygvocYYTjm8zJKYckS0JAoGAXbx5PvdwhgbbDBqsIHbf
25LS5yFP5NNvg6ua/vtp3h12h8VYpsFK7iiuxBKLQhfdvKU+McA0xz1XMN/nH4Y55u
26R4xWC8D8c/4IyydFVj4d2H+Ju5jWIytsm5yFFcU0/P5hHTovBvebJCBHtfMNmo0M
27AX0N/wYtzIVizEqh20s5ER0=
28-----END PRIVATE KEY-----

2. 构造签名串

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

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

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

以营销图片上传接口为例,

第一步,获取HTTP请求的方法

1POST

第二步,获取请求的绝对URL,请注意需要去除域名部分。

1/brand/card-member/media/image-upload

第三步,获取发起请求时的系统当前时间戳,即格林威治时间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)。

对于图片上传接口来说,参与签名计算的请求报文主体为meta的json串,其中meta字段包含了2个参数,一个是filename,一个是file_digest

为了演示,本文提供了一张示例图片,请下载并跟着一步步操作

先计算图片的摘要值

1openssl dgst -sha256 wechatpay_logo.png
2SHA256(wechatpay_logo.png)= d2973a45b1d528c21ebb77792ef3fcea40fa9a4e04a17e35369102ba9c84c8b1

拼接请求报文参与签名计算的请求主体为meta的json串,如下

1{"filename":"wechatpay_logo.png","file_digest":"d2973a45b1d528c21ebb77792ef3fcea40fa9a4e04a17e35369102ba9c84c8b1"}

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

1POST\n 
2/brand/card-member/media/image-upload\n 
31554208460\n 
4593BEC0C930BF1AFEB40B4A08C8FB242\n 
5{"filename":"wechatpay_logo.png","file_digest":"d2973a45b1d528c21ebb77792ef3fcea40fa9a4e04a17e35369102ba9c84c8b1"}\n

3. 计算签名值

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

1$ echo -n -e \
2 'POST\n/brand/card-member/media/image-upload\n1554208460\n593BEC0C930BF1AFEB40B4A08C8FB242\n{"filename":"wechatpay_logo.png","file_digest":"d2973a45b1d528c21ebb77792ef3fcea40fa9a4e04a17e35369102ba9c84c8b1"}\n' \
3 | openssl dgst -sha256 -sign apiclient_test_key.pem \
4 | openssl base64 -A

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

1U+2mhmoxjcHQRS4+HNlqQW+b7an1JpjPoB/SRgNYC/EYMoZz41vnwUM4kpB3Rfj7/kWhInN2DGA0Ay3qjdMTC8b0NgEc4CvoOVeyupYA0aYGfN0VhrRyo8kgfHs69ozRymenyb5fWdt3vdaz//Hjns2XE/qxTgPLS6XAMsb6rcyZbqBlNuQXq2YwbNxp/5flnxm9kZHWP31lTkm8UWaKRA+vZqhNDNr2U3OzN7Y2isigYz2ZAMbHRW9sFYeyVWOLTkT7Mv5G//w8Dlfi5NrA2JtBC2cr81mz33RnXz2zJ9FIFsIAM/lSN0q8on0fzJU17ZhDDvK1Y0wzCW3LNqp3Vw==

4. 设置HTTP头

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

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

1Authorization: 认证类型 签名信息

具体组成为:

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

  2. 签名信息

    • 发起请求的品牌ID brand_id

    • 品牌API证书序列号serial_no,用于声明所使用的证书

    • 请求随机串nonce_str,和你上面构造签名串的随机串要保持一致

    • 时间戳timestamp,和你上面构造签名串的时间戳要保持一致

    • 签名值signature,上面算出来的签名值

注意:

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

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

1Authorization: WECHATPAY-BRAND-SHA256-RSA2048 brand_id="100XX",nonce_str="593BEC0C930BF1AFEB40B4A08C8FB242",signature="U+2mhmoxjcHQRS4+HNlqQW+b7an1JpjPoB/SRgNYC/EYMoZz41vnwUM4kpB3Rfj7/kWhInN2DGA0Ay3qjdMTC8b0NgEc4CvoOVeyupYA0aYGfN0VhrRyo8kgfHs69ozRymenyb5fWdt3vdaz//Hjns2XE/qxTgPLS6XAMsb6rcyZbqBlNuQXq2YwbNxp/5flnxm9kZHWP31lTkm8UWaKRA+vZqhNDNr2U3OzN7Y2isigYz2ZAMbHRW9sFYeyVWOLTkT7Mv5G//w8Dlfi5NrA2JtBC2cr81mz33RnXz2zJ9FIFsIAM/lSN0q8on0fzJU17ZhDDvK1Y0wzCW3LNqp3Vw==",timestamp="1554208460",serial_no="3493DE0D9BB4EB98A8C65EAA7E8EE887EC24B71A"

最终我们可以组一个包含了签名的HTTP请求了。

(1)请注意Authorization的timestamp="1554208460",serial_no="3493DE0D9BB4EB98A8C65EAA7E8EE887EC24B71A"必须和你计算签名是传入的值是一致的

(2)此处只是一个示例,用于大家参考计算的格式,由于示例密钥本身是不可用的,因此以下请求并不真正可用

注意:

图片上传接口http头部还需要设置 Content-Type:multipart/form-data

1curl -X POST \
2  https://api.mch.weixin.qq.com/brand/card-member/media/image-upload \
3  -H 'Authorization: WECHATPAY-BRAND-SHA256-RSA2048 brand_id="100XX",nonce_str="593BEC0C930BF1AFEB40B4A08C8FB242",signature="U+2mhmoxjcHQRS4+HNlqQW+b7an1JpjPoB/SRgNYC/EYMoZz41vnwUM4kpB3Rfj7/kWhInN2DGA0Ay3qjdMTC8b0NgEc4CvoOVeyupYA0aYGfN0VhrRyo8kgfHs69ozRymenyb5fWdt3vdaz//Hjns2XE/qxTgPLS6XAMsb6rcyZbqBlNuQXq2YwbNxp/5flnxm9kZHWP31lTkm8UWaKRA+vZqhNDNr2U3OzN7Y2isigYz2ZAMbHRW9sFYeyVWOLTkT7Mv5G//w8Dlfi5NrA2JtBC2cr81mz33RnXz2zJ9FIFsIAM/lSN0q8on0fzJU17ZhDDvK1Y0wzCW3LNqp3Vw==",timestamp="1554208460",serial_no="3493DE0D9BB4EB98A8C65EAA7E8EE887EC24B71A"' \
4  -H "Accept: application/json" \
5  -H "Content-Type: multipart/form-data" \
6  -H "Wechatpay-Serial: PUB_KEY_ID_1652966817968722569710052651413695"  \
7  -F file=@"/path/to/file" \
8  -F meta='{
9    "filename" : "测试图片.png",
10    "file_digest" : "6daa17dd5ead246aa122becf119a8f92ddb68da3931f28ad695882afe8b26d76"
11  }'