手把手教你接入支付寶支付

原文: 手把手教你接入支付寶支付

前一久作了支付寶支付,分享一下接入的詳細步驟吧,移動端和服務端demo源碼已上傳至GitHub,要下載的移步至文章末尾。
先給出支付寶官方文檔:https://docs.open.alipay.com/204/105051/html

適用場景

在App內集成支付寶支付。APP調用支付寶提供的SDK,SDK再調用支付寶APP內的支付模塊。若是用戶已安裝支付寶APP,商家APP會跳轉到支付寶中完成支付,支付完後跳回到商家APP內。若是用戶沒有安裝支付寶APP,商家APP內會調起支付寶網頁支付收銀臺,用戶登陸支付寶帳戶,支付完後展現支付結果。java

接入

1. 建立應用並獲取APPID

地址:https://open.alipay.com/platform/appManage.htm#/apps
git

建立應用後即生成應用的標識APPID
建立指南:https://docs.open.alipay.com/200/105310/

github

2. 添加App支付功能

從個人應用列表點擊應用對應的查看詳情按鈕進入web

添加完成後,若應用狀態爲開發中狀態,只能在沙箱環境下進行調試。應用申請上線後,會同時申請此列表的功能,接口即生效。算法

注:手機端支付能夠添加 APP支付 和手機網站支付。APP支付使用原生開發,調用支付寶支付SDK。手機網站支付是在網頁中調用支付寶,因此使用h5+mui方式開發APP可以使用此功能,無需跳轉至原生。這裏根據須要酌情選擇。

數據庫

3. 簽約

在功能列表中點擊簽約,簽約後才能正常使用,簽約前可以使用沙箱模式進行調試。express




以上的步驟能夠交給公司相關人員進行申請,開發人員請看下面api


密鑰配置

1. 支付寶密鑰處理體系

因此須要獲取到應用公鑰、應用私鑰以及支付寶公鑰:數組

應用公鑰
由商戶本身生成的RSA公鑰(與應用私鑰必須匹配),商戶需上傳應用公鑰到支付寶開放平臺,以便支付寶使用該公鑰驗證該交易是不是商戶發起的。

應用私鑰
由商戶本身生成的RSA私鑰(與應用公鑰必須匹配),商戶開發者使用應用私鑰對請求字符串進行加簽。

支付寶公鑰
支付寶的RSA公鑰,商戶使用該公鑰驗證該結果是不是支付寶返回的。


2. 獲取密鑰和密鑰配置

步驟: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調用。


客戶端(Android)SDK集成

集成方法:https://docs.open.alipay.com/204/105296/

(1)發起支付請求

支付寶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)條。


(2)支付回調

調用支付寶支付後,將會收到同步通知和異步通知。若是過程當中取消支付則只會收到同步通知。

同步通知:支付寶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);



服務端(.Net)SDK集成

集成方法:https://docs.open.alipay.com/54/106370/

爲了便於支付寶異步接口調用,這裏服務端將使用webApi,服務端主要工做爲加簽、驗籤(異步通知驗證)以及更改訂單支付狀態。

(1)加簽

核心步驟:

//從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文件

pem文件是有格式的,就像這樣

-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAjayyr4gU38hr/EYnXdbEfbaGkdVnvf6Y+9zWkkiPcNq-----這裏是密鑰內容
-----END RSA PRIVATE KEY-----

生成pem文件須要使用openssl.exe這個可執行文件,固然也能夠copy個pem文件替換下里面的密鑰內容,不過這樣有可能會致使格式亂了。openssl.exe在密鑰生成工具的openssl的bin目錄下,雙擊便可打開。
openssl.png

生成應用私鑰pem文件,輸入命令:genrsa -out rsa_private_key.pem 2048

private_key_command.png
private_key_pem.png


生成應用公鑰pem文件,輸入命令:rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem

public_key_command.png
public_key_pem.png

支付寶公鑰須要上傳應用公鑰獲取,若是不使用pem文件,代碼中直接放上支付寶公鑰就行,若是要使用pem文件,能夠將應用公鑰的pem文件複製一份,將密鑰內容換成支付寶公鑰的,格式以下。

-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAADCBi----------這裏是支付寶公鑰
-----END PUBLIC KEY-----


注:上面密鑰的格式默認爲PKCS1的,若是使用PKCS8(Java適用)別忘記執行轉碼命令,不然也要涼涼的。若是使用沙箱模式請將密鑰換成沙箱版進行測試。


② 從pem文件中讀取密鑰

首先獲取存放密鑰文件的路徑,爲了防止出現意外,可獲取文件的絕對路徑,以下:

/// <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);



(2) 驗籤

當支付寶發送異步通知時,會將支付結果的信息異步返回至服務端,服務端須要進行驗籤操做,驗證請求是不是支付寶發送,並利用支付寶公鑰進行比對,保證交易的安全性和正確性。主要步驟以下:
①提供異步調用接口
支付寶異步通知將以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

相關文章
相關標籤/搜索