前一久作了支付寶支付,分享一下接入的詳細步驟吧,移動端和服務端demo源碼已上傳至GitHub,要下載的移步至文章末尾。
先給出支付寶官方文檔:https://docs.open.alipay.com/204/105051/html
在App內集成支付寶支付。APP調用支付寶提供的SDK,SDK再調用支付寶APP內的支付模塊。若是用戶已安裝支付寶APP,商家APP會跳轉到支付寶中完成支付,支付完後跳回到商家APP內。若是用戶沒有安裝支付寶APP,商家APP內會調起支付寶網頁支付收銀臺,用戶登陸支付寶帳戶,支付完後展現支付結果。java
地址:https://open.alipay.com/platform/appManage.htm#/apps
git
建立應用後即生成應用的標識APPID
建立指南:https://docs.open.alipay.com/200/105310/
github
從個人應用列表點擊應用對應的查看詳情按鈕進入web
添加完成後,若應用狀態爲開發中狀態,只能在沙箱環境下進行調試。應用申請上線後,會同時申請此列表的功能,接口即生效。算法
注:手機端支付能夠添加 APP支付 和手機網站支付。APP支付使用原生開發,調用支付寶支付SDK。手機網站支付是在網頁中調用支付寶,因此使用h5+mui方式開發APP可以使用此功能,無需跳轉至原生。這裏根據須要酌情選擇。
數據庫
在功能列表中點擊簽約,簽約後才能正常使用,簽約前可以使用沙箱模式進行調試。express
以上的步驟能夠交給公司相關人員進行申請,開發人員請看下面api
因此須要獲取到應用公鑰、應用私鑰以及支付寶公鑰:數組
①應用公鑰
由商戶本身生成的RSA公鑰(與應用私鑰必須匹配),商戶需上傳應用公鑰到支付寶開放平臺,以便支付寶使用該公鑰驗證該交易是不是商戶發起的。
②應用私鑰
由商戶本身生成的RSA私鑰(與應用公鑰必須匹配),商戶開發者使用應用私鑰對請求字符串進行加簽。
③支付寶公鑰
支付寶的RSA公鑰,商戶使用該公鑰驗證該結果是不是支付寶返回的。
步驟:https://docs.open.alipay.com/200/105310#s2
簽名專區:https://docs.open.alipay.com/291/106103/
密鑰生成工具:https://docs.open.alipay.com/291/106097/
注:使用密鑰生成工具生成密鑰時,要注意密鑰格式,若是服務端使用.Net或其餘非java語言,必定要選PKCS1(非JAVA適用),不然後面要涼涼。密鑰長度建議選擇2048。
使用App支付功能須要在原生中實現,這裏以Android爲例。接入移動支付須要集成兩個SDK,分別是客戶端的SDK和服務端的SDK。
SDK下載地址:
客戶端https://docs.open.alipay.com/54/104509
服務端https://docs.open.alipay.com/54/106370/
注:爲什麼須要兩個SDK?由於客戶端不能含有敏感信息,包括密鑰、APPID等,這些東西都必須從服務端獲取,包括加簽驗簽過程,因此還須要集成一個服務端給APP調用。
集成方法:https://docs.open.alipay.com/204/105296/
支付寶SDK中提供了一個PayTask類,使用其payV2方法便可發起支付請求。
/** * 支付(加簽過程不容許在客戶端進行,必須在服務端,不然有極大的安全隱患) * * @param orderInfo 加簽後的支付請求參數字符串(主要包含商戶的訂單信息,key=value形式,以&鏈接)。 */ private void pay(final String orderInfo) { final Runnable payRunnable = new Runnable() { @Override public void run() { PayTask alipay = new PayTask(MainActivity.this); //第二個參數設置爲true,將會在調用pay接口的時候直接喚起一個loading Map<String, String> result = alipay.payV2(orderInfo, true); Message msg = new Message(); msg.what = SDK_PAY_FLAG; msg.obj = result; mHandler.sendMessage(msg); } }; // 必須異步調用 Thread payThread = new Thread(payRunnable); payThread.start(); }
參數:
orderInfo: app支付請求參數字符串,主要包含商戶的訂單信息,key=value形式,以&鏈接。由衆多請求參數加簽以及非對稱加密後生成。
具體參數說明請看文檔:https://docs.open.alipay.com/204/105465/
因此發起支付請求的重點在於獲取orderInfo,也就是從服務端獲取加簽結果,加簽過程不容許在客戶端進行,不然可能被反編譯,形成嚴重的後果。因此加簽過程請看下面服務端(.Net)SDK集成的第(1)條。
調用支付寶支付後,將會收到同步通知和異步通知。若是過程當中取消支付則只會收到同步通知。
同步通知:支付寶sdk對商戶的請求支付數據處理完成後,會將結果同步反饋給app端。在支付回調中便可獲取支付結果信息。
異步通知: 對於App支付產生的交易,支付寶會根據原始支付API中傳入的異步通知地址notify_url,經過POST請求的形式將支付結果做爲參數通知到商戶系統。
注: 手機端同步通知有可能存在獲取不到的狀況,如手機關機,應用crash等狀況,因此手機端同步回調只做爲支付結果提示。真正的支付成功邏輯將在支付寶異步通知(服務端)中作處理,請看下面服務端(.Net)SDK集成的第(2)條。
so,手機端只作同步通知處理,以下:
Map<String, String> result = alipay.payV2(orderInfo, true);
result就是返回的同步回調結果,裏面的resultStatus是支付狀態碼,若是是9000則支付成功。
if (TextUtils.equals(resultStatus, "9000")) { // 該筆訂單是否真實支付成功,須要依賴服務端的異步通知。 showAlert(MainActivity.this, "支付成功" + payResult); } else { // 該筆訂單真實的支付結果,須要依賴服務端的異步通知。 showAlert(MainActivity.this, "支付失敗" + payResult); }
若是使用混合開發(h5+mui+原生),還需跳轉至mui頁面,則可以使用js回調函數將同步通知傳入mui端進行後續處理,如:
// 調用方法將原生代碼的執行結果返回給js層並觸發相應的JS層回調函數 JSUtil.execCallback(mWebview, CallBackID, resultStatus, JSUtil.OK, false);
集成方法:https://docs.open.alipay.com/54/106370/
爲了便於支付寶異步接口調用,這裏服務端將使用webApi,服務端主要工做爲加簽、驗籤(異步通知驗證)以及更改訂單支付狀態。
核心步驟:
//從pem文件中讀取 APP_PRIVATE_KEY = GetCurrentPathByAbs() + "rsa_private_key.pem"; ALIPAY_PUBLIC_KEY = GetCurrentPathByAbs() + "rsa_alipay_public_key.pem"; //最後一個參數爲false直接將私鑰內容寫入代碼,true從pem文件中讀取 IAopClient client = new DefaultAopClient(gateway, APPID, APP_PRIVATE_KEY, format, version, sign_type, ALIPAY_PUBLIC_KEY, CHARSET, true); //實例化具體API對應的request類,類名稱和接口名稱對應,當前調用接口名稱如:alipay.trade.app.pay AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest(); //SDK已經封裝掉了公共參數,這裏只須要傳入業務參數。如下方法爲sdk的model入參方式(model和biz_content同時存在的狀況下取biz_content)。 AlipayTradeAppPayModel model = new AlipayTradeAppPayModel(); model.Body = body; model.Subject = subject; model.TotalAmount = total_amount; model.ProductCode = product_code; model.OutTradeNo = out_trade_no; model.TimeoutExpress = timeout_express; request.SetBizModel(model); request.SetNotifyUrl(notify_url); //這裏和普通的接口調用不一樣,使用的是sdkExecute AlipayTradeAppPayResponse response = client.SdkExecute(request); string resp = response.Body; return resp;
支付寶服務端SDK中提供了一個SdkExcute方法,須要傳入對應的request類AlipayTradeAppPayRequest。實例化IAopClient對象時須要傳入請求網關(gateway)、APPID、應用私鑰、支付寶公鑰、調用的接口版本、編碼方式、簽名算法類型以及是否從文件中讀取密鑰的一個bool類型值。
其中,簽名算法類型應和配置密鑰時選擇的類型一致,不然會加簽失敗。最後一個bool型參數,爲false直接從代碼中讀取密鑰,爲true則從pem文件中讀取。
若是以爲密鑰放在代碼中不夠安全的話,建議將密鑰存儲爲pem文件,執行加簽過程時從文件中讀出,作法以下:
pem文件是有格式的,就像這樣
-----BEGIN RSA PRIVATE KEY----- MIIEogIBAjayyr4gU38hr/EYnXdbEfbaGkdVnvf6Y+9zWkkiPcNq-----這裏是密鑰內容 -----END RSA PRIVATE KEY-----
生成pem文件須要使用openssl.exe這個可執行文件,固然也能夠copy個pem文件替換下里面的密鑰內容,不過這樣有可能會致使格式亂了。openssl.exe在密鑰生成工具的openssl的bin目錄下,雙擊便可打開。
生成應用私鑰pem文件,輸入命令:genrsa -out rsa_private_key.pem 2048
生成應用公鑰pem文件,輸入命令:rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem
支付寶公鑰須要上傳應用公鑰獲取,若是不使用pem文件,代碼中直接放上支付寶公鑰就行,若是要使用pem文件,能夠將應用公鑰的pem文件複製一份,將密鑰內容換成支付寶公鑰的,格式以下。
-----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAADCBi----------這裏是支付寶公鑰 -----END PUBLIC KEY-----
注:上面密鑰的格式默認爲PKCS1的,若是使用PKCS8(Java適用)別忘記執行轉碼命令,不然也要涼涼的。若是使用沙箱模式請將密鑰換成沙箱版進行測試。
首先獲取存放密鑰文件的路徑,爲了防止出現意外,可獲取文件的絕對路徑,以下:
/// <summary> /// 獲取私鑰公鑰的路徑(絕對路徑) /// </summary> /// <returns></returns> private static string GetCurrentPathByAbs() { return HttpRuntime.AppDomainAppPath.ToString() + "rsa/"; }
獲取到文件路徑後傳入IAopClient的構造函數中,並將最後一個參數置爲true便可。
IAopClient client = new DefaultAopClient(gateway, APPID, APP_PRIVATE_KEY, format, version, sign_type, ALIPAY_PUBLIC_KEY, CHARSET, true);
當支付寶發送異步通知時,會將支付結果的信息異步返回至服務端,服務端須要進行驗籤操做,驗證請求是不是支付寶發送,並利用支付寶公鑰進行比對,保證交易的安全性和正確性。主要步驟以下:
①提供異步調用接口
支付寶異步通知將以post的方式發起請求,因此咱們須要編寫一個webapi接口,並保證接口的正確性,以下:
/// <summary> /// 異步驗籤(客戶端支付後,支付寶服務器將異步調用此方法) /// 實際支付邏輯在此操做,支付寶服務端將保證調用到此接口 /// </summary> /// <returns></returns> [HttpPost] public string GetAsynchronousYanQian() { return AlipayUtil.AsynchronousYanQian(GetRequestPost()); }
這個接口地址即是加簽過程當中傳入的異步通知地址notify_url
②獲取異步通知結果並驗籤
官方文檔地址:https://docs.open.alipay.com/54/106370/
上面這個連接支付寶介紹瞭如何獲取通知參數並驗籤。可是部分代碼是錯的,請看我寫的。
獲取支付寶異步通知結果以下:
/// <summary> /// 獲取支付寶POST過來通知消息,並以「參數名=參數值」的形式組成數組 /// request回來的信息組成的數組 /// </summary> /// <returns></returns> public Dictionary<string, string> GetRequestPost() { int i = 0; IDictionary<string, string> sArray = new Dictionary<string, string>(); NameValueCollection coll; coll = Request.Form; String[] requestItem = coll.AllKeys; for (i = 0; i < requestItem.Length; i++) { sArray.Add(requestItem[i], Request.Form[requestItem[i]]); } return (Dictionary<string, string>)sArray; }
驗籤:
驗簽過程支付寶AlipaySignature類提供了驗籤方法RSACheckV1和RSACheckV2,區別就不細說,這裏使用RSACheckV1方法,第一個參數即是支付寶返回的異步通知結果,第二個參數傳入支付寶公鑰,一樣最後一個參數傳false從代碼讀取支付寶公鑰,傳true從pem 文件中讀取。
bool flag = AlipaySignature.RSACheckV1(result, ALIPAY_PUBLIC_KEY, CHARSET, sign_type, true);
驗簽結果返回一個bool值,若是驗籤成功返回true,不然false。
③通知支付寶
支付寶異步通知調用接口後,若是未收到成功反饋,將會在一段時間內重複發送異步通知,以保證服務端接收到異步通知。因此當驗籤成功並真正的改變訂單支付狀態後,須要給支付寶返回success。若是反饋給支付寶的字符不是success這7個字符,支付寶服務器會不斷重發通知,直到超過24小時22分鐘。通常狀況下,25小時之內完成8次通知(通知的間隔頻率通常是:4m,10m,10m,1h,2h,6h,15h)。
if (flag) { //驗籤成功,將數據庫中訂單的支付狀態改變 if (ChangePayState()) { //若是數據庫插入成功,通知支付寶已收到通知 return "success"; } else { return "fail"; } } else { return "fail"; }
注:若是在改變訂單支付狀態時須要的某些參數沒法獲取,能夠將其拼接在加簽過程當中某些不是很必要的參數裏,支付寶將在異步通知中返回。
以上即是支付寶支付的實現步驟,包括了移動端(原生)和服務端(.Net)。Demo已上傳至GitHub,有興趣的能夠下載:
移動端:https://github.com/yangxch/AlipayDemo
服務端:https://github.com/yangxch/AlipayServerAPIDemo
原創不易,轉載請註明:http://www.javashuo.com/article/p-vlezjhag-mo.html