支付宝极简收银台(无线快捷支付)SDK,PHP服务端接入经验
自2012年7月支付宝正式宣布将PC快捷支付与移动端打通后,历经了多次版本迭代。随后支付宝推出了极简收银台。
与旧版的无线快捷支付SDK相比,极简的请求和回调的参数和验签方式都有了很大的不同。
在与支付宝对接的过程也遇到了不少问题,和大家分享一下解决的过程。
旧版SDK:无线快捷支付(2012年11月前某版,本人未参与)
新版SDK:无线快捷支付 极简收银台 (2014年6月)
前期准备:
商户公钥,私钥(由商户自己生成,支付宝会提供生成工具,也可以自己使用openssl生成) ,商户保留商户私钥待用,商户公钥上传到支付宝平台。
支付宝公钥,私钥,支付宝自己保留支付宝私钥。支付宝公钥在商户上传商户公钥后会获得。
即:商户拥有:商户私钥,支付宝公钥
支付宝拥有:商户公钥,支付宝私钥
无线支付的流程:
1,移动端生成订单和支付参数(如订单金额等),使用商户私钥签名参数,然后请求支付宝支付。
2,支付宝收到请求后使用商户公钥验签请求参数,验签通过后让用户支付,用户支付完成后支付宝生成回调参数,并用支付宝私钥签名参数,然后回调商户。
3,回调分为2个部分,同步回调(回调到移动端),异步回调(回调到商户的服务端)。如果移动端在生成支付请求的参数中由notify_url这项,
例:notify_url=http://www.testpay.com/act=notify_return?order_id=12345,那么支
付宝在支付完成后会异步回调这个地址。
本人工程的业务逻辑:
由于支付签名需要用到商户私钥,存放在手机端APP中有安全问题,所以在我的工程中把商户私钥放在了服务端,支付请求的参数签名是由服务端完成的。
1.手机端导入支付宝SDK,当需要支付时手机端生成一些支付相关参数,传到商户服务端
2.服务端收到请求后在数据库生成实际订单,然后用商户私钥对支付参数进行签名,完成后同步返回手机端
3.手机端收到返回后使用支付宝SDK提供的函数请求支付宝支付,支付宝验签通过后让用户支付,支付完成后同步回调手机端(手机端报信息告诉用户支付宝那
边支付成功了),异步回调商户服务器(商户服务器收到回调后验签,验签通过后变更自己的订单状态及一些其他的后继业务)。
至此完成了整个无线支付业务。
下面来说说接入时遇到的一些问题:
1.新旧SDK支付请求待签名参数的区别
旧版:
$notify_url = urlencode(PAY_CENTER_DOMAIN. ‘/notify?oid=’. $out_trade_no); //异步回调地址
//组装待签名数据
$signData = ‘partner=”‘. $partner. ‘”&';
$signData .= ‘seller=”‘. $seller. ‘”&';
$signData .= ‘out_trade_no=”‘. $out_trade_no. ‘”&';
$signData .= ‘subject=”‘. $subject. ‘”&';
$signData .= ‘body=”‘. $body. ‘”&';
$signData .= ‘total_fee=”‘. $totalFee. ‘”&';
$signData .= ‘notify_url=”‘. $notify_url. ‘”‘;
新版:
$notify_url = urlencode(PAY_CENTER_DOMAIN. ‘/notify?oid=’. $out_trade_no); //异步回调地址
//组装待签名数据
$signData = ‘_input_charset=”utf-8″&'; //新增必填项 参数编码字符集 默认值:utf-8
$signData .= ‘body=”‘. $body. ‘”&';
$signData .= ‘notify_url=”‘. $notify_url. ‘”&';
$signData .= ‘out_trade_no=”‘. $out_trade_no. ‘”&';
$signData .= ‘partner=”‘. $partner. ‘”&'; //合作伙伴ID
$signData .= ‘payment_type=”1″&'; //新增必填项 支付类型 默认值:1(商品购买)
$signData .= ‘seller_id=”‘. $seller. ‘”&'; //修改必填项 卖家支付宝账号 参数名称从seller变更为seller_id
$signData .= ‘service=”mobile.securitypay.pay”&'; //新增必填项 接口名称。固定值。默认:mobile.securitypay.pay
$signData .= ‘subject=”‘. $subject. ‘”&';
$signData .= ‘total_fee=”‘. $totalFee. ‘”‘;
对比可以看到 除了一些新增参数以及seller参数修改为seller_id以外,最明显的区别旧版参数支持无序,新版参数要升序排序。
2.同步回调没有sign值,异步没有回调
请求支付宝支付成功以后正确的流程应该是手机端收到支付宝同步回调,服务端收到异步回调。但我们就碰到问题。
同步回调了,但是回调中的sign参数的值是空的,而且已没有异步回调服务端。
咨询了支付宝的技术人员后被告知是安全校验码没有上传(商户RSA公钥)。
旧版SDK一直用到现在,商户RSA公钥一直有上传的,怎么没上传呢?上了http://b.alipay.com查看PID后发现原来的RSA公钥确实
有上传,在“应用接入信息”一栏。但是现在在”Pid和key”一栏又多了一项“安全校验码”,其中也有RSA公钥上传。
上传以后回调就正常了。
不过让我百思不得其解的就是流程上说商户公钥私钥只在请求支付宝时使用,能成功支付就说明支付宝在验签请求时使用了商户上传的公钥,那为什么再回调的时候还需要“安全校验码”中上传RSA公钥呢?
3.异步回调,服务器验签不过
对于新旧2版SDK,支付宝提供了2把不同的支付宝公钥。那么当你有多个APP,老的APP使用旧版SDK,新的工程APP,但是异步回调服务器都是一 个,那么如何区分回调是用的哪版SDK,以便使用正确的支付宝公钥来验签呢?询问了2个支付宝技术给出的回答都不相同,一个说极简收银台回调是有个 service参数,旧版是没有的。一个说新旧版回调参数都是一样的。
查看代码发现可以通过“notify_data”来判断是不是新旧SDK,只有旧版SDK是有这个参数的,同时旧版是直接用”notify_data”来做验签的,如:
“notify_data”:”xxx@xxx.com<\/seller_email>
2088xxxxxxxxxxxx<\/partner>
1<\/payment_type>1xxxxxxxx10<\/buyer_email>
20140616xxxxxxxx<\/trade_no>2088xxxxxxxxxxxx1<\/quantity>30.00<\/total_fee>N<\/use_coupon>Y<\/is_total_fee_adjust>
30.00<\/price>20140616xxxxxxxxxxxx<\/out_trade_no>2014-06-16 xx:xx:xx<\/gmt_create>2088xxxxxxxxxxxx<\/seller_id>xxxxxxxxxxxxxxxxxxxxx<\/subject>
WAIT_BUYER_PAY<\/trade_status>0.00<\/discount><\/notify>”
可以看到,值是XML格式的(转义符表在意,为了显示方便,实际是没的)。验签对象就是notify_data=”notify_data_value”。
而极简收银台则不是,对于服务端来说,要自己来拼接验签参数,即:去掉sign,sign_data参数,去掉notify_url里的参数,比如 你的回调地址是http://www.aaa.com/notify?order_id=123456,那么支付宝回调时候其实是形如:
http://www.aaa.com/notify?order_id=123456&dicount=0.01&seller_email=xxx@xxx.com&seller_id=2088xxxxxx……
那么在$_POST中会有$_POST[‘order_id’]这项,因为这项在notify_url中的参数,所以验签时候也不需要。
如果你的notify_url形如:http://www.bbb.com/1234567.html,那么就不会有这种问题。
其他都保留(包括notify_id),保留下来的字段按照键名升序排序。然后再以&拼接,如:k1=v1&k2=v2&… 此串字符就是所要验签的对象。
转载请注明出处:http://www.momohaha.com