1. 程式人生 > >React Native (IOS和Android) 支付寶和微信支付整合實戰(支付寶服務端篇)

React Native (IOS和Android) 支付寶和微信支付整合實戰(支付寶服務端篇)

序言React Native無論是在社群和應用程度上,在國內外是十分廣泛和普及的。而支付寶和微信在支付模組上都有或多或少的支援,雖然沒有完整的Demo,不過在我做過一個相關整合的專案後,在此我把相關的步驟和方法總結出來和大家分享,希望能夠幫助大家少走彎路,快速整合。

支付寶——服務端整合

一、獲取你的AppId和配置支付寶公鑰私鑰

在登入螞蟻金服開放平臺後,獲取你App應用對應的APPID (它目前就是在App圖示旁的一串數字)。
緊接著你就需要去配置你的公鑰私鑰了,具體步驟可以參考官方文件,寫的很清楚。

不過需要注意的有以下幾點:

1.如果你的服務端用的是非Java語言的,一定要選擇對應的金鑰格式,本分享用的是NodeJS寫的服務端,至於金鑰長度,1024,或者2048均可,建議以2048,所以選擇如下圖:

2.點選生成金鑰後,你會發現金鑰已經生成,分別為商戶應用私鑰和商戶應用公鑰,兩者請都妥善保管至其他資料夾中。

3.在螞蟻金服開放平臺,開發者中心,該APP應用下的介面加簽方式中,選擇 RSA(SHA256)金鑰 方式,並且上傳該第二步驟產生的應用公鑰並儲存

4.再次開啟支付寶生成金鑰工具,並且切換至【格式轉換】選項卡中,將第二步驟產生的商戶私鑰貼上至商戶應用私鑰中,並點選轉PKCS1(非JAVA適用)私鑰,它會提示該私鑰已經為該格式(如果你是JAVA適用的請選擇前者),我們重複該步驟的目的是為了生成供NodeJS可以讀取並且解析的PEM檔案(其他語言亦然),接著開啟金鑰檔案路徑,開啟私鑰檔案,你會發現,檔案頭會有 --BEGIN RSA PRVIATE KEY -- 字樣。   

5. 儲存該檔案並且重新命名alipay_private_key.pem。

6. 將私鑰和公鑰上傳至支付寶開發的應用後,獲取支付寶公鑰,儲存並且建立檔案為alipay_public_key.pem 在開頭和結尾分別加上 

-----BEGIN PUBLIC KEY-----
-----END PUBLIC KEY-----

至此,金鑰配置已經完成。




PS: 支付寶也有沙箱應用,其公鑰私鑰配置一模一樣,在此不再贅述

二、編寫服務端程式碼

支付寶生成請求引數可以參考官方文件https://docs.open.alipay.com/204/105465/  ,其中公共引數和業務引數是一般支付時所需要的。在服務端生成簽名其中有幾個比較重要的點,一定要牢記,反覆檢查,避免驗簽過程一直失敗,導致無法支付,浪費開發時間。(如果你的服務端語言是Java,.Net或者Php,那麼恭喜你,無需看以下內容,因為支付寶有相關SDK使用,

https://docs.open.alipay.com/54/103419

1.生成簽名sign之前的引數字串(暫且稱為未簽名支付串),一定要ASCII碼遞增排序

2.生成簽名後的sign引數放置未簽名支付串末尾(簽名支付串),其中未簽名支付串的引數個數和值不能有任何改動

3.將簽名支付串進行encode。

可參考NodeJS程式碼如下:

raw = function (args) {
        //升序引數,並且拼接為key & value字串
        var keys = Object.keys(args);
        keys = keys.sort()
        var newArgs = {};
        keys.forEach(function (key) {
            newArgs[key] = args[key];
        });
        var string = '';
        for (var k in newArgs) {
            string += '&' + k + '=' + newArgs[k];
        }
        string = string.substr(1);
        return string;
    }
// 支付寶生成簽名
var signed = function (order) {
    const app_id = ''; //此app_id為你申請的支付寶的應用APPID

    //生成一個基本的訂單資訊,必要的引數和值如下,更多引數和用法請參考官方文件

    var biz_content = '{"timeout_express":"60m",' +  //允許支付的最晚時間
        '"product_code":"QUICK_MSECURITY_PAY",' +
        '"total_amount":"' + order.total_amount + '",' + //支付金額,以元為單位
        '"subject":"' + order.subject + '",' +
        '"body":"' + order.body + '",' +
        '"out_trade_no":"' + order.out_trade_no + '"}'; //自己平臺的支付訂單號碼


    var unsigned = {
        app_id: app_id,
        method: 'alipay.trade.app.pay',
        charset: 'utf-8',
        sign_type: 'RSA2',
        version: '1.0',
        timestamp: moment().format('YYYY-MM-DD HH:mm:ss'),
        biz_content: biz_content,
        notify_url: 'http://192.168.1.45:3000/alipay/notify_url' //此處為支付寶服務端呼叫成功後通知你時會訪問的url
    }
    var unsignedStr = raw(unsigned);

    let private_key = fs.readFileSync('./config/alipay_private_key.pem'); //獲取商戶應用私鑰
    let signer = crypto.createSign('RSA-SHA256');  //建立RSA2加密演算法示例
    signer.update(unsignedStr);  //新增需要加密的字串
    let sign = signer.sign(private_key, 'base64');  //加密並且以base64的形式返回

    return qs.stringify(unsigned) + '&sign=' + encodeURIComponent(sign)    //encode
}
//收到支付寶非同步通知進行驗籤
var verified = function (response, sign) {
    let public_key = fs.readFileSync('./config/alipay_public_key.pem');
    var verify = crypto.createVerify('RSA-SHA256');
    verify.update(response);
    return verify.verify(public_key, sign, 'base64')

}
//支付寶獲取簽名的訂單資訊
alipay.post('/pay', function (req, res) {
    var signedStr = signed({
        body: '測試支付',//預祝春節快樂,1分錢購,贈送IPhone X一人一部
        subject: '測試支付',//免費贈送IPhone X
        out_trade_no: '70501111111S501115',  //自己平臺的支付訂單號碼
        total_amount: '0.01'       //支付金額,以元為單位
    })

    res.send(signedStr);
})
//接受支付寶通知
alipay.post('/notify_url', function (req, res) {
    var obj = req.body
    var sign = req.body.sign
    delete obj['sign']
    delete obj['sign_type']

    var verRes = verified(raw(obj), sign)
    if (verRes) {
        /** 
         * 1、商戶需要驗證該通知資料中的out_trade_no是否為商戶系統中建立的訂單號,
         * 2、判斷total_amount是否確實為該訂單的實際金額(即商戶訂單建立時的金額)
         * 3、校驗通知中的seller_id(或者seller_email) 是否為out_trade_no這筆單據的對應的操作方(有的時候,一個商戶可能有多個seller_id/seller_email)
         * 4、驗證app_id是否為該商戶本身。上述1、2、3、4有任何一個驗證不通過,則表明本次通知是異常通知,務必忽略。在上述驗證通過後商戶必須根據支付寶不同型別的業務通知,
         * 正確的進行不同的業務處理,並且過濾重複的通知結果資料。
         * 在支付寶的業務通知中,只有交易通知狀態為TRADE_SUCCESS或TRADE_FINISHED時,支付寶才會認定為買家付款成功。
        */
        //按照支付結果非同步通知中的描述,對支付結果中的業務內容進行1\2\3\4二次校驗,校驗成功後在response中返回success,校驗失敗返回failure
        res.send('success')
    } else {
        res.send('failure')
    }
})

至此支付寶服務端程式碼已經完成,由於本地開發notify_url必須為能夠被訪問的地址,如果想本地測試,建議可以使用ngrok

鳴謝:我是一名來自盛安德的Shinetecher,感謝盛安德公司及同事們對IT技術的支援,分享和熱情,讓我有時間和動力完成此博文。

聯絡:歡迎各位朋友有任何問題和建議留言至此部落格下,或者新增本人微訊號:liyijia428 進行溝通交流學習