2

Python3.7.2+Django2.0.4 美多商城集成最新版支付宝支付接口(2019.04)

 11 months ago
source link: https://v3u.cn/a_id_64
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Python3.7.2+Django2.0.4 美多商城集成最新版支付宝支付接口(2019.04)

首页 - Python/2019-04-10

  最新版支付宝算法的改变就是RSA升级了RSA2,长度推荐2048,其他的逻辑变化不大,关于秘钥的生成在之前的一篇文章已经有所介绍

  在Django中集成支付接口的前置操作就是需要安装pycryptodome
  pip3 install -i https://pypi.douban.com/simple pycryptodome
  然后将之前生成好的私钥和公钥(注意这里的公钥是指支付宝公钥),放入到项目目录中去
  
20190410090428_54822.png

  文档地址:https://docs.open.alipay.com/api

  然后根据支付宝官网文档写一个支付基类 pay.py
     
from datetime import datetime
from Crypto.PublicKey import RSA
from Crypto.Signature import PKCS1_v1_5
from Crypto.Hash import SHA256
from urllib.parse import quote_plus
from urllib.parse import urlparse, parse_qs
from base64 import decodebytes, encodebytes
import json

class AliPay(object):
    """
    支付宝支付接口(PC端支付接口)
    """

    def __init__(self, appid, app_notify_url, app_private_key_path,
                 alipay_public_key_path, return_url, debug=False):
        self.appid = appid
        self.app_notify_url = app_notify_url
        self.app_private_key_path = app_private_key_path
        self.app_private_key = None
        self.return_url = return_url
        with open(self.app_private_key_path) as fp:
            self.app_private_key = RSA.importKey(fp.read())
        self.alipay_public_key_path = alipay_public_key_path
        with open(self.alipay_public_key_path) as fp:
            self.alipay_public_key = RSA.importKey(fp.read())

        if debug is True:
            self.__gateway = "https://openapi.alipaydev.com/gateway.do"
        else:
            self.__gateway = "https://openapi.alipay.com/gateway.do"

    def direct_pay(self, subject, out_trade_no, total_amount, return_url=None, **kwargs):
        biz_content = {
            "subject": subject,
            "out_trade_no": out_trade_no,
            "total_amount": total_amount,
            "product_code": "FAST_INSTANT_TRADE_PAY",
            # "qr_pay_mode":4
        }

        biz_content.update(kwargs)
        data = self.build_body("alipay.trade.page.pay", biz_content, self.return_url)
        return self.sign_data(data)

    def build_body(self, method, biz_content, return_url=None):
        data = {
            "app_id": self.appid,
            "method": method,
            "charset": "utf-8",
            "sign_type": "RSA2",
            "timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
            "version": "1.0",
            "biz_content": biz_content
        }

        if return_url is not None:
            data["notify_url"] = self.app_notify_url
            data["return_url"] = self.return_url

        return data

    def sign_data(self, data):
        data.pop("sign", None)
        # 排序后的字符串
        unsigned_items = self.ordered_data(data)
        unsigned_string = "&".join("{0}={1}".format(k, v) for k, v in unsigned_items)
        sign = self.sign(unsigned_string.encode("utf-8"))
        # ordered_items = self.ordered_data(data)
        quoted_string = "&".join("{0}={1}".format(k, quote_plus(v)) for k, v in unsigned_items)

        # 获得最终的订单信息字符串
        signed_string = quoted_string + "&sign=" + quote_plus(sign)
        return signed_string

    def ordered_data(self, data):
        complex_keys = []
        for key, value in data.items():
            if isinstance(value, dict):
                complex_keys.append(key)

        # 将字典类型的数据dump出来
        for key in complex_keys:
            data[key] = json.dumps(data[key], separators=(',', ':'))

        return sorted([(k, v) for k, v in data.items()])

    def sign(self, unsigned_string):
        # 开始计算签名
        key = self.app_private_key
        signer = PKCS1_v1_5.new(key)
        signature = signer.sign(SHA256.new(unsigned_string))
        # base64 编码,转换为unicode表示并移除回车
        sign = encodebytes(signature).decode("utf8").replace("\n", "")
        return sign

    def _verify(self, raw_content, signature):
        # 开始计算签名
        key = self.alipay_public_key
        signer = PKCS1_v1_5.new(key)
        digest = SHA256.new()
        digest.update(raw_content.encode("utf8"))
        if signer.verify(digest, decodebytes(signature.encode("utf8"))):
            return True
        return False

    def verify(self, data, signature):
        if "sign_type" in data:
            sign_type = data.pop("sign_type")
        # 排序后的字符串
        unsigned_items = self.ordered_data(data)
        message = "&".join(u"{}={}".format(k, v) for k, v in unsigned_items)
        return self._verify(message, signature)
    最后在视图文件中定义方法就可以了
#导入支付基类
from .pay import Alipay

#初始化阿里支付对象
def get_ali_object():
    # 沙箱环境地址:https://openhome.alipay.com/platform/appDaily.htm?tab=info
    app_id = "2016092600603658"  #  APPID (沙箱应用)

    # 支付完成后,支付偷偷向这里地址发送一个post请求,识别公网IP,如果是 192.168.20.13局域网IP ,支付宝找不到,def page2() 接收不到这个请求
    notify_url = "http://localhost:8000/md_admin/alipayreturn"

    # 支付完成后,跳转的地址。
    return_url = "http://localhost:8000/md_admin/alipayreturn"

    merchant_private_key_path = "c:/Users/liuyue/www/md/keys/app_private_2048.txt" # 应用私钥
    alipay_public_key_path = "c:/Users/liuyue/www/md/keys/alipay_public_2048.txt"  # 支付宝公钥

    alipay = AliPay(
        appid=app_id,
        app_notify_url=notify_url,
        return_url=return_url,
        app_private_key_path=merchant_private_key_path,
        alipay_public_key_path=alipay_public_key_path,  # 支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥
        debug=True,  # 默认False,
    )
    return alipay



def page1(request):

    if request.method == "POST":

        # 根据当前用户的配置,生成URL,并跳转。
        money = float(request.POST.get('money'))

        alipay = get_ali_object()

        # 生成支付的url
        query_params = alipay.direct_pay(
            subject="test",  # 商品简单描述
            out_trade_no="myorder" + str(time.time()),  # 用户购买的商品订单号(每次不一样) 20180301073422891
            total_amount=money,  # 交易金额(单位: 元 保留俩位小数)
        )

        pay_url = "https://openapi.alipaydev.com/gateway.do?{0}".format(query_params)  # 支付宝网关地址(沙箱应用)

        return redirect(pay_url)
    else:
        return render(request,'md_admin/page1.html')


def alipay_return(request):
    alipay = get_ali_object()
    params = request.GET.dict()
    sign = params.pop('sign', None)
    status = alipay.verify(params, sign)
    print('==================开始==================')
    print('GET验证', status)
    print('==================结束==================')
    return HttpResponse('支付成功')

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK