Signing SDKs签名工具包
Ready-made signing and verification code for eight languages.八种语言的签名与验签代码,可直接集成。
Ready-made code for the signing rules in Signing: one self-contained file per language, standard library only, no package to install. Copy it into your project. Every file has the same functions and a built-in self-test against the published test vector.
把 签名 的签名规则写好的现成代码:每种语言一个独立文件,只用标准库,不需要装任何包,拷进项目即可。每个文件的函数一致,并自带一个按公开测试向量做的自检。
Downloads下载
| Language语言 | File文件 | Requires要求 | Self-test自检 |
|---|---|---|---|
| Python | merchant_sign.py | 3.8+ | python3 merchant_sign.py |
| Node.js | merchant-sign.js | 18+ | node merchant-sign.js |
| Go | merchantsign.go · merchantsign_test.go | 1.21+ | go test ./merchantsign |
| Java | MerchantSign.java | 11+ | java MerchantSign.java |
| PHP | MerchantSign.php | 7.4+ | php MerchantSign.php |
| C# / .NET | MerchantSign.cs | .NET 6+ | MerchantSign.SelfTest() |
| Ruby | merchant_sign.rb | 2.6+ | ruby merchant_sign.rb |
| bash + openssl | merchant-sign.sh | bash, openssl, curl | bash merchant-sign.sh |
A passing self-test prints self-test passed e5273ee9…6589: it reproduces the test vector, accepts a correctly signed request, and refuses a tampered body, another merchant code and a timestamp outside the window.
自检通过会打印 self-test passed e5273ee9…6589:能算出测试向量,接受签对的请求,拒绝改过的正文、别的商户编码和超窗的时间戳。
Functions函数
Names follow each language's style (signed_headers in Python and Ruby, signedHeaders in Node.js, Java and PHP, SignRequest / SignedHeaders in Go and C#).
函数名按各语言习惯(Python、Ruby 是 signed_headers,Node.js、Java、PHP 是 signedHeaders,Go、C# 是 SignRequest / SignedHeaders)。
| Function函数 | Use it to用途 |
|---|---|
signedHeaders(merchantCode, secretKey, method, path, rawBody) | Call the Platform API: the five headers (Content-Type, X-Merchant-Code, a new X-Request-Id, X-Timestamp, X-Signature). Send exactly rawBody.调平台接口:生成五个请求头(Content-Type、X-Merchant-Code、新的 X-Request-Id、X-Timestamp、X-Signature)。正文必须原样发 rawBody。 |
verify(secretKey, merchantCode, headers, method, path, rawBody) | Serve the Wallet API: checks the headers are present, X-Merchant-Code is yours, the timestamp is within ±300 s and the signature matches (constant-time). Returns OK, INVALID_SIGNATURE or TIMESTAMP_EXPIRED — answer the last two as the envelope code.实现钱包接口:检查请求头齐全、X-Merchant-Code 是自己的、时间戳在 ±300 秒内、签名一致(常量时间比较)。返回 OK、INVALID_SIGNATURE 或 TIMESTAMP_EXPIRED,后两个直接作为信封的 code 回给平台。 |
sign(secretKey, method, path, merchantCode, timestamp, requestId, rawBody) | The raw algorithm, for debugging against the test vector.算法本身,排查时对照测试向量用。 |
stringToSign(…) · bodySha256(rawBody) | The two intermediate values: log them when a signature does not match.两个中间值:签名对不上时把它们打出来比对。 |
newRequestId() | 32 random hex characters; a new one for every request, retries included.32 位随机十六进制;每个请求(含重试)都换新的。 |
envelope(code, message, data) | The JSON response body for your Wallet API (not in Java and C#: use your JSON library).钱包接口的响应正文(Java、C# 没有,用自己的 JSON 库)。 |
When a signature does not match签名对不上时
- Sign the exact bytes you send. Re-serialising JSON (key order, spaces, escaped
/or Unicode) changes the hash. PATHis the path only: no host, no query string, same case. For the Wallet API it includes the path part of yourcallbackUrl.X-Merchant-Code,X-TimestampandX-Request-Idgo into the string to sign byte-for-byte as sent.- Compare your
bodySha256andstringToSignwith the test vector; then check that the secret key has no trailing space or newline.
- 签的必须是实际发出的那份字节。重新序列化 JSON(键顺序、空格、转义的
/或 Unicode)会让哈希变。 PATH只是路径:不含域名和查询串,大小写一致。钱包接口要带上callbackUrl自己的路径部分。X-Merchant-Code、X-Timestamp、X-Request-Id按发出去的原样进待签字符串。- 先把自己的
bodySha256与stringToSign和测试向量对一遍,再看密钥两端有没有多出的空格或换行。