自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