tencent cloud

腾讯云超级应用服务

动态与公告
【2025年1月2日】关于腾讯云小程序平台更名为腾讯云超级应用服务的公告
控制台更新动态
Android SDK 更新动态
iOS SDK 更新动态
Flutter 更新动态
IDE 更新动态
基础库更新动态
产品简介
产品概述
产品优势
应用场景
购买指南
计费概述
按量计费(后付费)
续费指引
停服说明
快速入门
套餐管理
概述
控制台账号管理
存储配置
加速配置
品牌化配置
平台功能
控制台登录
用户和权限体系
小程序管理
小游戏管理
应用管理
商业化
平台管理
用户管理
团队管理
运营管理
安全中心
代码接入指引
Demo 及 SDK 获取
Android
iOS
Flutter
App 服务端接入指南
GUID 生成规则
小程序开发指南
小程序介绍与开发环境
小程序代码组成
指南
框架
组件
API
服务端
JS SDK
基础库
IDE 使用指南
小游戏开发指南
指南
API
服务端
实践教程
小程序登录实践教程
小程序订阅消息实践教程
支付相关实践教程
广告接入实践教程
小游戏订阅消息实践教程
相关协议
数据处理和安全协议

签名以及验签

PDF
聚焦模式
字号
最后更新时间: 2025-12-31 16:24:49

支付请求验签名算法说明

商户调用 superapp 支付相关接口的时候需要用到商户 API 证书构造请求签名,且根据请求参数类型的不同,签名方式有所差异,请参考以下的操作指引说明。

如何构造请求签名

获取商户 API 证书

构造请求签名需要使用商户 API 证书。
此处我们已经拿到了商户 API 证书,并且将对应的商户 API 私钥 apiclient_key.pem,保存在了本地。
商户号:202003191046
证书序列号:526807E51G82219FOC2D5D3E6AB8ED1S8SDS8787AS
API 证书私钥:您需要将以下文件保存为 pem 格式,为了避免大家和自己的真实的公私钥混淆,此处将其保存为 apiclient_test_key.pem。
注意:
以下只是一个示例密钥,实际上并不可用。
-----BEGIN PRIVATE KEY-----\\nMIIEuwIBADALBgkqhkiG9w0BAQEEggSnMIIEowIBAAKCAQEA1WFrv7DQ2FeBB2ZR\\n/bh+W/38+Rgcs/yxTdd0/9r5DWYvB6Lhc0pqaNnrmZUc+Uih6CELe1K3AAvg0+6A\\njfcLV/aqNx4xdwqfLt2P1F7TsyGJZWMe5OoPmwzel8zRpGcqY/WdmevEEFqmIc/r\\nWVa1fOCM9eIzP9QQbgT7tKXa/ixi5B5y8B0pShYJuyE2M8GimvbDbnaatMQJlwFP\\nO9fxU7cRZBdkDcUB8dMxl2ZfTHZjEC6ypR4Ux5vnPIB9hH7qHFbc6W9ueEfVRTk3\\neeoVnbmZJHliWBqtv89Tm0uMk+fD2ZayRA+TuwFajt0NTcbnM6kM0cuuyEyd7bnE\\nWFKuAwIDAQABAoIBACS+8CVEt9Jpz0iM8FW3Ldt9s9DZvCeqvoXfMsDU3srV7Adu\\nn1CRYh3IWXBLY3/yaB9ngWitZ+JUKVWV3wGTp5pwWgO/6VjMtXkGorw50E8q2VRi\\na3GUdTeIUdTmarvbIEuygn99QHhog++StL7f1cU5jkzRtW2qgWHQ7d/AKCRZA+R1\\nnUwNaQHdz2Fn5a5cQsULgNCf0Rfn4MxgsvGl3ZVcJVUiumEDfV2TDcLz2wEaWvTo\\nOhD6bN+Ug0LuucmuwC9FzR7DUNxWxmQpAdPMbAfku47K9ARqHfUjNXtBUktGdo6x\\nfmdm/fNTodSzziu4Sn87iQU0R7VU8TT2Wx1l/jECgYEA3/3yqEWSwjCY/hs+rq9O\\nrhF4vVyd8az7X+KCKiYZl51oRiRSso8dWvuVixpx3ZW8vp81K2eq9h6BmuePMVZK\\nH8PV8LbNbuLUn/cTREo7JcT0jUFSfwyMiu6De23fyCSb3fM4EFdjuywTn0d+RIr5\\nlnurFc8mRWTTX0E+kht7K50CgYEA899JYDMqs7GU+Gg8vNEHL3ux4VIGWaV0LPFj\\nn4UNn0aT3t0M+OgWm9K1tCSi5PPkmkAt8wCOtKPmSiq1CQeWa8HX+JHkMiEYO6Ki\\nHecXmZlUr/yXMhCTkkxwNsFAFxP1KYOm91+ka6w+l7/qcjan+WZsYT2XpSTx0LV5\\nPma8Hh8CgYABUNuZE3eOPnzXmU9f9VWv/hhIfH/NCKgdYxZCqyChXGJdbx8xP1f7\\nzdiODaS3mYaXVBYa4CwH8BvwzgVwU8Jxt1PNazV/vkNjgS8SyqDYUvTg045pgqhc\\ntJP/KKEU6uojfqdIqUrDsbmXyPK78lkPAkD6CtJ9u97mA1sbvp+VnQKBgFp41qba\\ntJfPZJ23RfkibtD9yaL2pCZzzCK0NqpCWShirY77YMmiiGishf5brRbVKFTVRHan\\nGUoIl/Gh4GGGMBav5ihwL0Etp+jPz+baCZZRHOrhAVJwdd7LfsHBdb5aCBSro7CY\\nCc5sKxhu+VH/1tceWUzF5dE9YHx2JpGw2U8vAoGBAL2Wp4S2dA+zKfhX7QOCLl3q\\nXYujhL1dgZBaDonWtOrn7llLSqaryD/TH8C6QRVrsXpLdwuSLx7tzQnG81ptO49Q\\nuCVFbGF5RwCf8Wq8OlYuJ/MS9GsE+Ux2EYVX3DD5zV6gtN11c7NsTEan9fRpgZjt\\n2kuvKl1oec/Rh8fbmqid\\n-----END PRIVATE KEY-----

构造签名串

我们希望商户的技术开发人员按照当前文档约定的规则构造签名串。superapp 支付会使用同样的方式构造签名串。如果商户构造签名串的方式错误,将导致签名验证不通过。下面先说明签名串的具体格式。
签名串一共有5个部分,每一行为一个参数。结尾以\\n(换行符,ASCII 编码值为0x0A)结束,包括最后一行。如果参数本身以\\n结束,也需要附加一个\\n。
HTTP请求方法\\n
URL\\n
请求时间戳\\n
请求随机串\\n
请求报文主体\\n
1. 请求参数里带 Path 参数
以查询订单接口为例
第一步,获取 HTTP 请求的方法
GET
第二步,获取请求的绝对 URL
查询订单接口的 URL 为/v3/pay/transactions/out-trade-no/{out_trade_no},path里面带了参数 out_trade_no,这里需要填上实际的商户订单号,例如1217752501201407033233368018
/v3/pay/transactions/out-trade-no/1217752501201407033233368018
第三步,获取发起请求时的系统当前时间戳
即格林威治时间1970年01月01日00时00分00秒(北京时间1970年01月01日08时00分00秒)起至现在的总秒数,作为请求时间戳。superapp 支付会拒绝处理很久之前发起的请求,请商户保持自身系统的时间准确。
date +%s
1554208460
第四步,生成一个请求随机串
E6F165123B4E32D8D0D6
第五步,获取请求中的请求报文主体(request body)
对于该接口来说,请求报文主体是一个空串,只需要附加一个 \\n 即可
第六步,按照前述规则构造的请求签名串
POST\\n
/v3/pay/transactions/jsapi\\n
1554208460\\n
E6F165123B4E32D8D0D6\\n
{"appid":"wxd678efh567hg6787","mchid":"1230000109","description":"Image","out_trade_no":"1217752501201407033233368018","notify_url":"https://www.weixin.qq.com/wxpay/pay.php","amount":{"total":100,"currency":"USD"},"payer":{"openid":"oUpF8uMuAJO_M2pxb1Q9zNjWeS6o"}}\\n
2. 请求参数里带 Body 参数
以下单接口为例
第一步,获取 HTTP 请求的方法
POST
第二步,获取请求的绝对 URL,请注意需要去除域名部分
/v3/pay/transactions/jsapi
第三步,获取发起请求时的系统当前时间戳
即格林威治时间1970年01月01日00时00分00秒(北京时间1970年01月01日08时00分00秒)起至现在的总秒数,作为请求时间戳。superapp 支付会拒绝处理很久之前发起的请求,请商户保持自身系统的时间准确。
date +%s
1554208460
第四步,生成一个请求随机串
E6F165123B4E32D8D0D6
第五步,获取请求中的请求报文主体(request body)
您可以将所有参数放在一行,对应的发起签名请求的时候 body 参数也应该放在一行。
您也可以将参数以多行计算签名,对应发起请求的时候 body 参数也要是多行。即您计算签名时 body 是怎么样的,您发起请求时 body 就应该是怎么样的。
这里以将所有参数放到一行做演示
{"appid":"wxd678efh567hg6787","mchid":"1230000109","description":"describe","out_trade_no":"1217752501201407033233368018","notify_url":"https://${domain}/wxpay/pay.php","amount":{"total":100,"currency":"USD"},"payer":{"openid":"oUpF8uMuAJO_M2pxb1Q9zNjWeS6o"}}
第六步,按照前述规则构造的请求签名串
POST\\n
/v3/pay/transactions/jsapi\\n
1554208460\\n
E6F165123B4E32D8D0D6\\n
{"appid":"wxd678efh567hg6787","mchid":"1230000109","description":"describe","out_trade_no":"1217752501201407033233368018","notify_url":"https://${domain}/wxpay/pay.php","amount":{"total":100,"currency":"USD"},"payer":{"openid":"oUpF8uMuAJO_M2pxb1Q9zNjWeS6o"}}
当请求报文主体是一个空串时,只需要附加一个\\n即可。
3. 请求参数里带 Query 参数
以商户订单号查询订单
第一步,获取 HTTP 请求的方法
GET
第二步,获取请求的绝对 URL,请注意需要去除域名部分
拼接您的 Query(查询参数),假设您的 query 参数如下
limit=52offset=103authorized_data={"business_type":"FAVOR_STOCK", "stock_id":"2433405"}4partner={"type":"APPID","appid":"wx4e1916a585d1f4e9","merchant_id":"2480029552"}
(1)先对 authorized_data 参数和 partner 参数做个 URL encodeURL
limit=52offset=103authorized_data%3D%7B%22business_type%22%3A%22FAVOR_STOCK%22%2C%20%22stock_id%22%3A%222433405%22%7D4partner%3D%7B%22type%22%3A%22APPID%22%2C%22appid%22%3A%22wx4e1916a585d1f4e9%22%2C%22merchant_id%22%3A%222480029552%22%7D
(2)拼接您的请求 URL,查询参数需要在末尾加'?'和对应的查询字符串,多个字符串之间用&符号连接(请注意以下 URL 是在一行,因为排版原因可能看起来像换行,实际数据在一行)
/v3/pay/transactions/out-trade-no/112233445566?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秒)起至现在的总秒数,作为请求时间戳。superapp 支付会拒绝处理很久之前发起的请求,请商户保持自身系统的时间准确。
date +%s
1554208460
第四步,生成一个请求随机串
E6F165123B4E32D8D0D6
第五步,获取请求中的请求报文主体(request body)
请求报文主体是一个空串,只需要附加一个\\n即可。
第六步,按照前述规则构造的请求签名串
当请求报文主体是一个空串时,只需要附加一个\\n即可。
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\\n 31554208460\\n E6F165123B4E32D8D0D6\\n \\n

计算签名值

绝大多数编程语言提供的签名函数支持对签名数据进行签名。强烈建议商户调用该类函数,使用商户私钥对待签名串进行 SHA256 with RSA 签名,并对签名结果进行 Base64 编码得到签名值。
请注意处理单双引号转义问题,第二行的外层是单引号,则里面的参数不需要转义,如果第二行最外层使用了双引号,则 body 参数的双引号都需要转义。
1. 设置 HTTP 头
请求通过 HTTP Authorization 头来传递签名。Authorization 由认证类型和签名信息两个部分组成。
下面我们使用命令行演示如何生成签名。
Authorization: 认证类型 签名信息
具体组成为:
2. 认证类型,目前为 WECHATPAY2-SHA256-RSA2048
3. 签名信息,参数参考开发必要参数说明
发起请求的商户(包括直连商户、服务商或渠道商)的商户号 mchid。
商户 API 证书序列号【serial_no】,用于声明所使用的证书。
请求随机串 nonce_str,和您上面构造签名串的随机串要保持一致。
时间戳 timestamp,和您上面构造签名串的时间戳要保持一致。
签名值 signature,上面算出来的签名值。
注意:
以上五项签名信息,无顺序要求。
Authorization 头的示例如下:(注意,示例因为排版可能存在换行,实际数据应在一行)
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"
最终我们可以组一个包含了签名的 HTTP 请求了。
(1)请注意第六行的 body 参数必须在一行,不能换行,因为签名计算签名时 body 就是以一行来计算签名的,这里发起请求时需要和签名时的保持一致。
(2)请注意 Authorization的timestamp="1554208460",serial_no="408B07E79B8269FEC3D5D3E6AB8ED163A6A380DB" 必须和您计算签名时传入的值是一致的。
(3)此处只是一个示例,用于大家参考计算的格式,由于示例密钥本身是不可用的,因此以下请求并不真正可用
curl -X POST \\
https://${domain}/openserver/v3/pay/transactions/jsapi \\
-H 'Authorization: WECHATPAY2-SHA256-RSA2048 mchid="202003191046",nonce_str="E6F165123B4E32D8D0D6",signature="gEuexJ547PHFV77TQ6eiE4tphVYfWfUe1Wc2dBmVnoMYU2rl/M4zhw+b3vBhuMw6AC7pteNkryLA7UWU2h+umo0OdSuuLm1++O3NckQPCSfm6dypsjn4GYm84KMqXWFrhFmyxEwIdEJDr3w1UYfxOcu55OQupfLkrt/ZzuOspnliJFrPzGQFUk7lGqMMtpz3EfbDUNxnVsHblORg3hVmuYNmbGWnS2ovU30Y2Q+iKFDxzkaXBk8LTy6HzvxizRo6Q+J4SVM7O0hKXfgo1QdI68kpzNULb3EVBXlhTyPUzhkHzzLxECL1qHl3HH2hEv8++C+4wBlsagF3j/O6PABojA==",timestamp="1554208460",serial_no="408B07E79B8269FEC3D5D3E6AB8ED163A6A380DB"' \\
-H 'Accept: application/json' \\
-H 'Content-Type: application/json' \\
-d '{"appid":"mp1bfa1hnwvaluqb","mchid":"202003191046","description":"goods desc","out_trade_no":"84ssadasd125e32463542341342","notify_url":"https://mini.demo.com/pay/callback:","amount":{"total":100,"currency":"USD"},"payer":{"openid":"oae60e19213a17344EhDZBb25849"}}'

支付回调签名

superapp 支付用 superapp 支付平台证书私钥对"响应签名串"进行 SHA256 with RSA 签名,并对签名结果进行 Base64 编码得到签名值。

构造签名串

1、按照以下规则构造应答的验签名串。签名串共有三行,行尾以\\n 结束,包括最后一行。\\n 为换行符(ASCII 编码值为 0x0A)。若应答报文主体为空(如 HTTP 状态码为 204 No Content),最后一行仅为一个 \\n 换行符。
请求时间戳\\n
请求随机串\\n
请求报文主体\\n

计算签名值

绝大多数编程语言提供的签名函数支持对签名数据进行签名。强烈建议调用该类函数,使用平台证书私钥对待签名串进行 SHA256 with RSA 签名,并对签名结果进行 Base64 编码得到签名值。
请注意处理单双引号转义问题,第二行的外层是单引号,则里面的参数不需要转义,如果第二行最外层使用了双引号,则 body 参数的双引号都需要转义。

支付回调数据加密

为了保证安全性,superapp 支付在回调通知接口中,对关键信息进行了 AES-256-GCM 加密,商户收到报文后,要解密出明文,APIv3 密钥是解密时使用的对称密钥。本章节详细介绍了加密报文的格式,以及如何进行解密。

1. 加密报文格式

AES-GCM 是一种 NIST 标准的认证加密算法, 是一种能够同时保证数据的保密性、 完整性和真实性的一种加密模式。它最广泛的应用是在 TLS 中。
证书和回调报文使用的加密密钥为 APIv3 密钥。
对于加密的数据,我们使用了一个独立的 JSON 对象来表示。为了方便阅读,示例做了 Pretty 格式化,并加入了注释。
{
"original_type": "transaction", // 加密前的对象类型
"algorithm": "AEAD_AES_256_GCM", // 加密算法
// Base64编码后的密文
"ciphertext": "...",
// 加密使用的随机串初始化向量)
"nonce": "...",
// 附加数据包(可能为空)
"associated_data": ""
}


帮助和支持

本页内容是否解决了您的问题?

填写满意度调查问卷,共创更好文档体验。

文档反馈