自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)