1. 文档说明
1.3. 签名规则
用户可以在HTTP请求中增加 Authorization 的Header来包含签名(Signature)信息,表明这个消息已被授权。
HmacUtils.hmacSha1Hex( (1)
key, (2)
verb + "\n" + (3) (4)
resource + "\n" + (5)
body + "\n" + (6)
timestamp + "\n"); (7)
1 | 使用hmacSha1进行签名转16进制 |
2 | key 为AccessKeySecret,表示签名所需的密钥,该密匙是在控制台生成 |
3 | verb 表示HTTP 请求的Method,主要有PUT,GET,POST,HEAD,DELETE等 |
4 | \n 表示换行符 |
5 | resource 为参数拼接串,内容为请求接口的 path+?+query |
6 | body 表示请求体的json完整json内容 |
7 | timestamp 表示时间戳表示此次操作的时间,且必须为GMT格式, 如"Sun, 22 Nov 2015 08:16:38 GMT",该时间戳也将加入到 Header 中,键为 Date |
没有请求体的HttpMethod的签名body用空字符串
HmacUtils.hmacSha1Hex("3zKciJOwhWE4SSRUxXzCsABcIhJWd5Gb",
"POST" + "\n" +
"/charges?a=a&b=b&c=c" + "\n" +
"{"a":"a","b":"b","c":"c"}" + "\n" +
"Sun, 22 Nov 2015 08:16:38 GMT" + "\n"
再将签名前面加入accessKeyId进行base64编码,在结果前面加入Basic+空格组成Authorization
"Basic " + Base64.encodeBase64String((accessKeyId + ":" + signature).getBytes()));
Content-Type:application/json; charset=UTF-8
Authorization:Basic NTgzMTM1NDZlZjE5MGM1MWMwYmVhYzZmOjA2NzY2NTUwMzdhOTQyZDc5M2JjOGM5YzRmNzE5M2QzZTRhYjY5YjE=
Date:Tue, 13 Dec 2016 03:22:13 GMT
1.4. 验签规则
为防止黑客伪造交易结果给商户造成损失,PayingCloud对所有发给商户的交易结果异步通知都进行了RSA签名,并将签名进行Base64编码后放在Http请求头 sign 中,开发者需要使用SHA1WithRSA算法和PayingCloud提供的RSA公钥对其进行验证:
// 从异步通知请求头中获取签名
String sign = request.getHeader("sign");
// 对签名Base64解码
byte[] signBytes = Base64.decodeBase64(sign)
// 获取异步通知请求体
String content = ...
// 对请求体进行UTF-8字符解码
byte[] contentBytes = content.getBytes("UTF-8")
// 采用SHA1WithRSA算法进行验证
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
byte[] encodedKey = Base64.decodeBase64(PayingCloud.DEFAULT_PUBLIC_KEY); // 使用PayingCloud提供的RSA公钥
PublicKey key = keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));
Signature signature = Signature.getInstance("SHA1WithRSA"); // 验签算法SHA1WithRSA
signature.initVerify(key);
signature.update(contentBytes);
return signature.verify(signBytes);
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCPymtLbRkHgvVfUT933LrwWns6YZHLPpT1pP9TKJ+cgIZiQwZ4mtqoqPHSVtiT5HA8fwFzWuJ/6qWaQhER7TOISUFUHZlHyBjNK/Z5px6PNB7rT4OrLP0KuZ7nuX5qdnOKuAbrj1MBLSinOHQ8tDJhPrPKxuZlKw3SeL5auHlKWwIDAQAB
2. API接口
2.1. 付款接口
2.1.3. 请求参数
变量名 | 必填 | 类型 | 示例值 | 描述 |
---|---|---|---|---|
mer_order_no |
是 |
String(32) |
20150806125346 |
商户系统内部订单号,要求8到32个字符、且在同一个应用下唯一,只能包含字母和数字 |
subject |
是 |
String(128) |
iPhone7-32G |
商品详情 |
total |
是 |
Int |
888 |
订单总金额,单位为分,不能小于1 |
currency |
是 |
String(16) |
GBP |
币种代码,符合ISO4217标准详见货币类型表 |
channel |
是 |
Enum |
CREDIT_CARD |
渠道类型,具体枚举值详见[渠道类型] |
external_customer_id |
否 |
String |
oUpF8uMuAJO_M2pxb1Q9zNjWeS6o |
用户在商户的唯一标识 |
user_ip |
是 |
String(16) |
123.12.12.123 |
终端IP,APP和网页支付提交用户端ip。 |
extra |
是 |
Map<String, Object> |
{"returnUrl": "https://api.payingcloud.cn/returnUrl"} |
渠道额外参数,用键值对的map存储不同渠道之间的渠道额外参数 |
notifyUrl |
是 |
String(100) |
https://api.payingcloud.cn/callback |
异步通知地址,支付成功后返回支付结果地址。 |
3. 备注
3.1. 渠道类型表
名称 | 描述 |
---|---|
UMF_CREDIT_CARD |
UMF_信用卡支付 |
UMF_DEBIT_CARD |
UMF_借记卡支付 |
UMF_WECHAT_SCAN |
UMF_微信扫码支付 |
UMF_WECHAT_WEB |
UMF_用户在微信浏UMF_览器里支付订单. |
UMF_WECHAT_IN_APP |
UMF_用户在App应用里支付订单. |
UMF_ALIPAY_SCAN |
UMF_支付宝扫码支付 |
WX_CODE |
微信扫码支付 |
WX_APP |
微信APP支付 |
WX_JSAPI |
微信公众号支付 |
3.2. 交易凭证样例
"url":"<form name=\"punchout_form\"method=\"post\" action=\"https://pay.yizhifubj.com/prs/user_payment.checkit?v_md5info=b00a57dc732366cbfed3da03fe064af5&v_orderstatus=1&v_rcvname=9466&v_moneytype=0&v_oid=20161222-9466-585b77b5ab5c986f049a0faa&v_ymd=20161222&v_url=http%3A%2F%2F127.0.0.1%3A9000%2Forder%2Fcharge%2Freturn&v_rcvaddr=9466&v_ordername=9466&v_rcvtel=9466&v_mid=9466&v_amount=0.01&v_rcvpost=9466\">\n<input type=\"submit\" value=\"[0xe7][0xab][0x8b][0xe5][0x8d][0xb3][0xe6][0x94][0xaf][0xe4][0xbb][0x98]\" style=\"display:none\" >\n</form>\n<script>document.forms[0].submit();</script>"
3.3. 交易凭证详情
-
BDPAY_WEB
-
BDPAY_WAP
-
从credentials中获取键: url
-
servletResponse.sendRedirect(charge.getCredentials().get("url"));
-
ALIPAY_DIRECT
-
BJPAY_WEB
-
CHINAPAY_WEB
-
JDPAY_WEB
-
JDPAY_WAP
-
YEEPAY_WAP
-
ALIPAY_WAP
-
从credentials中获取键: html(utf-8)
-
servletResponse.setContentType("text/html;charset=UTF-8");
servletResponse.getWriter().write(charge.getCredentials().get("html"));
-
YEEPAY_WEB
-
从credentials中获取键: html(gbk)
-
servletResponse.setContentType("text/html;charset=gbk");
servletResponse.getWriter().write(charge.getCredentials().get("html"));
-
BDPAY_QR
-
从credentials中获取键: url(图片地址)
-
-
WXPAY_NATIVE
-
BJPAY_WX
-
ALIPAY_QR
-
KFTPAY_WX
-
KFTPAY_ALI
-
JDPAY_QR
-
CMBCPAY_T0_ALI
-
CMBCPAY_T1_ALI
-
CMBCPAY_T0_WX_QR
-
CMBCPAY_T1_WX_QR
-
CMBCPAY_T0_QQ
-
CMBCPAY_T1_QQ
-
WEBANKPAY_WX_QR
-
从credentials中获取键: codeUrl(生成二维码的字符串)
-
-
WXPAY_JSAPI
-
CMBCPAY_T0_WX_JSAPI
-
CMBCPAY_T1_WX_JSAPI
-
WEBANKPAY_WX_JSAPI
-
从credentials中获取键:
-
appId
-
timeStamp
-
nonceStr
-
package
-
signType
-
paySign
-
-
在页面调用微信jsSDk 详情见 微信公众号h5调用文档
3.4. 渠道额外参数
变量名 | 必填 | 描述 | 约束 |
---|---|---|---|
sub_orders |
是 |
子订单,每个子订单只能是相同的商品类型。 |
对象数组,详细 sub_order |
goods_type |
是 |
商品分类 |
枚举值:01 充值; 02 消费 |
receiver_name |
是 |
收货人姓名 |
字符串,最大长度256 |
receiver_moblie_id |
是 |
收件人的电话号码 |
字符串,手机号格式 |
shipping_address |
是 |
送货地址 |
字符串,最大长度256 |
real_name |
是 |
商品实名制购买 |
枚举值:0 非实名制; 1 实名制 |
phone |
是 |
银行预留号码 |
字符串,手机号格式 |
card_holder |
是 |
持卡人姓名 |
字符串,加密。 |
citizen_id_type |
是 |
公民当前身份类型 |
枚举,IDENTITY_CARD |
citizen_id_number |
是 |
身份证号码 |
字符串,加密。 |
bank_code |
是 |
银行代码 |
16个大写英文字母或数字以内 |
number |
是 |
卡号 |
字符串,加密。 |
valid_date |
是 |
银行卡有效期 |
字符串,加密。 |
cvv2 |
是 |
银行卡安全码 |
字符串,加密。 |
变量名 | 必填 | 描述 | 约束 |
---|---|---|---|
sub_orders |
是 |
子订单,每个子订单只能是相同的商品类型。 |
对象数组,详细 sub_order |
goods_type |
是 |
商品分类 |
枚举值:01 充值; 02 消费 |
receiver_name |
是 |
收货人姓名 |
字符串,最大长度256 |
receiver_moblie_id |
是 |
收件人的电话号码 |
字符串,手机号格式 |
shipping_address |
是 |
送货地址 |
字符串,最大长度256 |
real_name |
是 |
商品实名制购买 |
枚举值:0 非实名制; 1 实名制 |
phone |
是 |
银行预留号码 |
字符串,手机号格式 |
card_holder |
是 |
持卡人姓名 |
字符串,加密。 |
citizen_id_type |
是 |
公民当前身份类型 |
枚举,IDENTITY_CARD |
citizen_id_number |
是 |
身份证号码 |
字符串,加密。 |
bank_code |
是 |
银行代码 |
16个大写英文字母或数字以内 |
number |
是 |
卡号 |
字符串,加密。 |
变量名 | 必填 | 描述 | 约束 |
---|---|---|---|
sub_orders |
是 |
子订单,每个子订单只能是相同的商品类型。 |
对象数组,详细 sub_order |
goods_type |
是 |
商品分类 |
枚举值:01 充值; 02 消费 |
receiver_name |
是 |
收货人姓名 |
字符串,最大长度256 |
receiver_moblie_id |
是 |
收件人的电话号码 |
字符串,手机号格式 |
shipping_address |
是 |
送货地址 |
字符串,最大长度256 |
real_name |
是 |
商品实名制购买 |
枚举值:0 非实名制; 1 实名制 |
phone |
是 |
支付人手机号 |
字符串.手机号格式 |
name |
是 |
支付人姓名 |
字符串.最大长度128,加密。 |
citizen_id_type |
是 |
公民当前身份类型, 枚举值为IDENTITY_CARD |
枚举。 |
citizen_id_number |
是 |
身份证号码 |
字符串,加密。 |
open_id |
是 |
OpenID是为每个合作用户的唯一微信id, 不同的用户有单独的OpenID. |
字符串 |
变量名 | 必填 | 描述 | 约束 |
---|---|---|---|
sub_orders |
是 |
子订单,每个子订单只能是相同的商品类型。 |
对象数组,详细 sub_order |
goods_type |
是 |
商品分类 |
枚举值:01 充值; 02 消费 |
receiver_name |
是 |
收货人姓名 |
字符串,最大长度256 |
receiver_moblie_id |
是 |
收件人的电话号码 |
字符串,手机号格式 |
shipping_address |
是 |
送货地址 |
字符串,最大长度256 |
real_name |
是 |
商品实名制购买 |
枚举值:0 非实名制; 1 实名制 |
phone |
是 |
支付人手机号 |
字符串.手机号格式 |
name |
是 |
支付人姓名 |
字符串.最大长度128,加密。 |
citizen_id_type |
是 |
公民当前身份类型, 枚举值为IDENTITY_CARD |
枚举。 |
citizen_id_number |
是 |
身份证号码 |
字符串,加密。 |
变量名 | 必填 | 描述 | 约束 |
---|---|---|---|
mer_sub_reference_id |
是 |
子订单对象的id |
字符串,最大长度16,最小长度4。 |
sub_total |
是 |
子订单的总金额 |
字符串,最大长度10, 两位小数。 |
trans_code |
是 |
商品的交易码 |
字符串,最大长度8,最小长度4。 |
is_customs |
是 |
商户是否需要UMF向用户提交付款信息 |
字符串 |
invoice_id |
是 |
子订单收据 |
字符串,最大长度20。 |
mer_item_id |
是 |
商户系统id |
字符串,最大长度32。 |
type |
是 |
商品类型 |
枚举值 |
name |
否 |
商品名称 |
字符串,最大长度256。 |
description |
否 |
商品描述 |
字符串,最大长度64。 |
mer_total |
是 |
单个商品的金额 |
字符串,最大长度10, 两位小数。 |
quantity |
是 |
商品的数量 |
字符串 |
变量名 | 必填 | 类型 | 示例值 | 描述 |
---|---|---|---|---|
attach |
否 |
String(127) |
深圳分店 |
附加数据,在查询API和支付通知中原样返回,该字段主要用于商户携带订单的自定义数据 |
detail |
否 |
String(6000 |
{ "goods_id":"iphone6s_32G", "wxpay_goods_id":"1002", "goods_name":"iPhone6s 32G", "quantity":1,"price":608800, "goods_category":"123789", "body":"苹果手机" } |
商品详细列表,使用Json格式 |
goods_tag |
否 |
String(32) |
WXG |
订单优惠标记,代金券或立减优惠功能的参数. |
product_id |
否 |
String(32) |
1.22354E+22 |
trade_type=NATIVE,此参数必传。 此id为二维码中包含的商品ID,商户自行定义。 |