第三方支付开发支付功能Python 运维

支付宝移动支付服务器异步通知 python 实现

2016-02-29  本文已影响2955人  闪了腰的企鹅

支付宝移动支付成功后,支付宝会给商户端预先设置的 notifyURL 发送异步通知,商户端收到支付状态的异步通知后,需要给支付宝返回商户端的处理状态。

简单逻辑如下(服务器异步通知方面逻辑):

  1. 移动App通过支付宝发起支付
  2. 支付宝服务端向商户端发送支付状态
  3. 商户端验证支付宝发来的请求的签名
  4. 商户端验证请求是否来源支付宝
  5. 商户端反馈支付宝处理结果

涉及 Python 库 rsa 和 requests

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

主要代码如下(Django环境):

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()
        # �验证签名 sign
        if alipay.verifySignString(request.POST):
            notify_id = request.POST['notify_id']
            parter = request.POST['seller_id']
            # 验证是否是支付宝发来的通知
            if alipay.verifyURL(parter,notify_id):
                # 处理服务器端逻辑,更新数据库等
                # ...
                # ...
                # ...
                print '-------- pay success ------------'
                # 向支付宝返回�成功接收并处理异步通知状态
                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'

# 验证是否是支付宝发来的通知链接地址
ALIPAY_REMOTE_ORIGIN_URL = 'https://mapi.alipay.com/gateway.do'

class AliPay():

# 验证签名 
# 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 经过 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:
        # �支付宝当前仅支持 RSA 加密,未来也许会有其他类型
        return False

    return False

# 验证是否是支付宝发来的通知
# 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

注意点就是,支付宝返回的 sign 是 base64 encode 过的,需要先 decode,再调用方法 <code>rsa.verify()</code>

上一篇下一篇

猜你喜欢

热点阅读