支付寶移動(dòng)支付服務(wù)器異步通知 python 實(shí)現(xiàn)

支付寶移動(dòng)支付成功后,支付寶會(huì)給商戶端預(yù)先設(shè)置的 notifyURL 發(fā)送異步通知,商戶端收到支付狀態(tài)的異步通知后,需要給支付寶返回商戶端的處理狀態(tài)。

簡(jiǎn)單邏輯如下(服務(wù)器異步通知方面邏輯):

  1. 移動(dòng)App通過(guò)支付寶發(fā)起支付
  2. 支付寶服務(wù)端向商戶端發(fā)送支付狀態(tài)
  3. 商戶端驗(yàn)證支付寶發(fā)來(lái)的請(qǐng)求的簽名
  4. 商戶端驗(yàn)證請(qǐng)求是否來(lái)源支付寶
  5. 商戶端反饋支付寶處理結(jié)果

涉及 Python 庫(kù) rsa 和 requests

rsa: <code>pip install rsa</code>
requests: <code>pip install requests</code>

主要代碼如下(Django環(huán)境):

view.py:
# ...
import AlipayHelper as AliPay
# ...

@csrf_exempt
def paycallbackAliPay(request):
    if request.method == 'POST':
        if not len(request.POST) > 0:
            return HttpResponse(status=400)
        alipay = AliPay.AliPay()
        # ?驗(yàn)證簽名 sign
        if alipay.verifySignString(request.POST):
            notify_id = request.POST['notify_id']
            parter = request.POST['seller_id']
            # 驗(yàn)證是否是支付寶發(fā)來(lái)的通知
            if alipay.verifyURL(parter,notify_id):
                # 處理服務(wù)器端邏輯,更新數(shù)據(jù)庫(kù)等
                # ...
                # ...
                # ...
                print '-------- pay success ------------'
                # 向支付寶返回?成功接收并處理異步通知狀態(tài)
                return HttpResponse("SUCCESS")
    return HttpResponse(status=400)

AlipayHelper.py

# -*- coding: utf-8 -*-

import rsa
import base64
import requests

# 支付寶 RSA 公鑰
ALIPAY_RSA_PUBLIC_KEY_PATH = 'alipay_rsa_public_key.pem'

# 驗(yàn)證是否是支付寶發(fā)來(lái)的通知鏈接地址
ALIPAY_REMOTE_ORIGIN_URL = 'https://mapi.alipay.com/gateway.do'

class AliPay():

# 驗(yàn)證簽名 
# params:request.POST
def verifySignString(self,params):
    if not len(params) > 0:
        return False
    key_sorted = sorted(params.keys())
    content = ''
    sign_type = params["sign_type"]
    signOrigin = params["sign"]

    for key in key_sorted:
        if key not in ["sign","sign_type"]:
            if len(params[key]) > 0:
                content = content + key + "=" + params[key] + "&"
    content = content[:-1]
    content = content.encode("utf-8")
    # print "content -> " + content

    if sign_type.upper() == "RSA":
        try:
            with open(ALIPAY_RSA_PUBLIC_KEY_PATH) as publickfile:
                pub = publickfile.read()
            pubkey = rsa.PublicKey.load_pkcs1_openssl_pem(pub)

            # ?支付寶返回的 sign 經(jīng)過(guò) base64 encode,先 decode 一下
            signatureString = base64.decodestring(signOrigin)
            if rsa.verify(content, signatureString, pubkey):
                # print "----------verify sign success----------"
                return True
        except Exception,e:
            # print "----------verify sign failed----------"
            return False
    else:
        # ?支付寶當(dāng)前僅支持 RSA 加密,未來(lái)也許會(huì)有其他類(lèi)型
        return False

    return False

# 驗(yàn)證是否是支付寶發(fā)來(lái)的通知
# partner:request.POST["seller_id"],也可以 hardcode
# notify_id:request.POST["notify_id"]
def verifyURL(self, partner, notify_id):
    payload = {'service':'notify_verify','partner':partner,'notify_id':notify_id}
    urlString = ALIPAY_REMOTE_ORIGIN_URL
    r = requests.get(urlString,params=payload)
    result = r.text
    # print result
    if result.upper() == "TRUE":
        # print "----------verify ?url success----------"
        return True
    return False

注意點(diǎn)就是,支付寶返回的 sign 是 base64 encode 過(guò)的,需要先 decode,再調(diào)用方法 <code>rsa.verify()</code>

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容