Appearance
签名机制
TIP
强烈建议使用 SDK 进行签名计算和验证。
生成签名
签名内容
签名内容由七个参数拼接而成,每一个参数以 \n
(换行符)结束。包括最后一个参数,如果参数本身以 \n
结束,也需要附加一个 \n
。
Plain
AppId\nAppSecret\nHTTP请求方法\nURL\n请求时间戳\n请求随机串\n请求报文主体\n
签名内容示范:
Plain
483f6c9c743b4a9bbd34bee0c9c81eb7
19200e1478524aceb629acbc570d15d3
POST
http://gateway.examplepay.com/pg/v2/payment/create
1724932426000
3d4578d6c27186f31411ed01b870dffe
{"merchantTradeNo":"MTU-11677","amount":"1.00","currency":"INR","description":"payment test","payer":{"userId":"test_id","name":"testName","email":"[email protected]","phone":"00000000"},"payMethod":{"type":"UPI"},"tradeEnv":{"ip":"127.0.0.1","deviceId":"02efc74d-3988-4f0d-8cc8-0cb78bded719"},"merchantAttach":"merchant attach","notifyUrl":"https://example.com/notifyurl","returnUrl":"https://example.com/returnurl"}
TIP
请求报文主体参数格式为 JSON 字符串。生成请求报文主体时,请根据接口文档参数类型设定字段数据类型,可参考具体接口说明页面中的示例代码。
签名提交
通过标准的 HTTP Authorization 头提交。Authorization 由认证类型和签名信息两个部分组成。
Plain
# 格式
Authorization: 认证类型 签名信息
# 示范
Authorization:V2_SHA256 appId=4189b620f93b48c5904210ff47bb8938,sign=58c7f3ddbdeb80caa41e511aec154d16abbea448ba9278c49c0027becf7d2631,timestamp=1713515049457,nonce=B2DF764E7371B224FB3F144F1BD69A2A
- 认证类型,目前为 V2-SHA256
- 签名信息组成
- 格式:appId=%s,sign=%s,timestamp=%s,nonce=%s (%s 替换为实际值)
- appId:商户在商户自服务系统获取的应用ID
- sign:接口请求的签名值
- timestamp:时间戳(毫秒)
- nonce:请求随机串
- 以上签名字段信息,无顺序要求
签名计算
Java
package com.examplepay.sdk.authorization.example;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class SignDemo {
public static void main(String[] args) throws NoSuchAlgorithmException {
// 签名内容格式见上文
String signContent = "替换为签名内容";
String algorithm = "SHA-256";
MessageDigest messageDigest = MessageDigest.getInstance(algorithm);
messageDigest.update(signContent.getBytes(StandardCharsets.UTF_8));
byte[] byteBuffer = messageDigest.digest();
StringBuilder sb = new StringBuilder();
for (byte b : byteBuffer) {
String hex = Integer.toHexString(0xff & b);
if (hex.length() == 1) {
sb.append('0');
}
sb.append(hex);
}
String sign = sb.toString();
System.out.println(sign);
}
}
Webhook 场景
- 商户验证签名时,URL 取支付平台当前向商户系统发起请求地址。URL 应该为商户调用支付平台接口创建订单时填写的 notifyUrl。
- 其它同接口请求响应场景。
WARNING
验证签名时,请务必使用网关原始请求报文主体(HTTP Request Body)进行验证,以免经过解析转换后 null 或空值被过滤掉,和网关原始请求报文主体不一致,导致验证签名失败。
Return URL 跳转场景
- 从 queryString 中取出 payment 和 authorization 字段值。
- 按上文中的 Authorization 格式,取出签名信息。
- 解析签名信息,取出请求时间戳(timestamp)、请求随机串(nonce)。
- 按上文的签名内容格式,对 payment 字段值重新进行签名。签名内容格式为:
Plain
AppId\nAppSecret\nHTTP请求方法\nURL\n请求时间戳\n请求随机串\nQueryString\n
URL:为商户提交的原始 return url,不含平台跳转时附加的特定参数部分。特定参数为:payment/authorization/paymentNo/merchantTradeNo
QueryString 格式:
payment=%s, %s 为 payment 字段值
示例:
payment={"amount":"1.00","createdTime":"2024-04-23T21:15:29+08:00","currency":"INR","merchantAttach":"merchant attach","merchantTradeNo":"MTU-1150","paymentNo":"20240423211529300800001098000022","refundStatus":"NO_REFUND","status":"PENDING"}
- 与 authorization 字段值中的签名信息进行比较验证。