Flask-day11

一、登錄螞蟻金服網(wǎng)站

https://open.alipay.com/developmentAccess/developmentAccess.htm

二、配置沙箱應(yīng)用環(huán)境

沙箱應(yīng)用: 支付寶給開發(fā)者提供的調(diào)試環(huán)境應(yīng)用

  • 沙盒應(yīng)用界面

    image
  • 生成RSA密鑰
    支付寶提供一鍵生成工具便于開發(fā)者生成一對RSA密鑰.

    下載該工具后,解壓打開文件夾,運行“RSA簽名驗簽工具.bat”(WINDOWS)或“RSA簽名驗簽工具.command”(MAC_OSX)

生成的私鑰需妥善保管,避免遺失,不要泄露。應(yīng)用私鑰需填寫到代碼中供簽名時使用。應(yīng)用公鑰需提供給支付寶賬號管理者上傳到支付寶開放平臺。

  • 上傳自己的公鑰
    生成公鑰后,將公鑰填寫到信息配置

    image

上述中生成了生成RSA密鑰操作中,對應(yīng)的應(yīng)用公鑰2048.txt即是公鑰!

  • 保存支付寶公鑰
    將生成的支付寶公鑰,復(fù)制到一個txt文件中

    image
  • 秘鑰個數(shù)確定
    這樣我們就有了3個秘鑰,看下圖!

    image
  • 秘鑰文件的修改
    在秘鑰txt文件里,秘鑰內(nèi)容的頭部和結(jié)尾加上兩行字符串,注意所有秘鑰都要加。

-----BEGIN PRIVATE KEY-----
# 秘鑰內(nèi)容....
-----END PRIVATE KEY-----

后續(xù)方便操作,直接讀取文件即可

三、支付寶集成到項目

  • 基本流程
1\. 接收商品名稱信息、訂單金額、訂單號
2\. 請求支付寶預(yù)付訂單創(chuàng)建接口
3\. 根據(jù)返回的URL返回給客戶端
4\. 用戶支付
5\. 用戶支付完成之后,客戶端會跳轉(zhuǎn)到一個頁面(服務(wù)器預(yù)置頁面)
6\. 用戶支付完成之后,支付寶會調(diào)用回調(diào)(通知服務(wù)器)

  • 安裝
# 需要模塊加密方面的模塊
pip install pycryptodome   

  • 支付寶封裝及初始化配置 alipay/init.py
# __init__.py文件(直接拷貝)
from datetime import datetime
from Crypto.PublicKey import RSA
from Crypto.Signature import PKCS1_v1_5
from Crypto.Hash import SHA256
from base64 import b64encode, b64decode
from urllib.parse import quote_plus
from urllib.parse import urlparse, parse_qs
from urllib.request import urlopen
from base64 import decodebytes, encodebytes
import json

# 支付寶封裝(不需要做任何修改)
class AliPay(object):
    """
    支付寶支付接口
    """
    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.import_key(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 ordered_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)

        # 將字典類型的數(shù)據(jù)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 編碼,轉(zhuǎn)換為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)

# 初始化操作
# 設(shè)置秘鑰公鑰的存放路徑
app_private_key_path = os.path.join(BASE_DIR, 'alipay/ying_yong_si_yao.txt')
alipay_public_key_path = os.path.join(BASE_DIR, 'alipay/zhi_fu_bao_gong_yao.txt')
# 根據(jù)自己申請的進(jìn)行設(shè)置 
alipay = AliPay(
    appid="2016091800542542",  # 設(shè)置簽約的appid
    app_notify_url="http://112.74.55.3/notify/",   # 異步支付通知url
    app_private_key_path=app_private_key_path,  # 設(shè)置應(yīng)用私鑰
    alipay_public_key_path=alipay_public_key_path,  # 支付寶的公鑰,驗證支付寶回傳消息使用,不是你自己的公鑰,
    debug=True,  # 默認(rèn)False,            # 設(shè)置是否是沙箱環(huán)境,True是沙箱環(huán)境
    return_url="http://112.74.55.3/result/",   # 同步支付通知url,在這個頁面可以展示給用戶看,只有付款成功后才會跳轉(zhuǎn)
)

備注: return_url 和 notify_url的區(qū)別  
    return_url: 
        如果設(shè)置了return_url,買家付款成功后會跳到return_url所在頁面;
        在這個頁面可以展示給用戶看,只有付款成功后才會跳轉(zhuǎn);

    notify_url:
        服務(wù)器后臺通知,這個頁面是程序后臺運行的(買家和賣家都看不到);
        買家付完款后,支付寶會調(diào)用notify_url這個頁面所在的頁面并把相應(yīng)的參數(shù)傳遞到這個頁面;
        這個頁面根據(jù)支付寶傳遞過來的參數(shù)修改網(wǎng)站訂單的狀態(tài),更新完訂單后需要在頁面上;
        打印出一個success給支付寶,如果反饋給支付寶的不是success,支付寶會繼續(xù)調(diào)用這個頁面;

  • 應(yīng)用公鑰(設(shè)置自己應(yīng)用的公鑰) alipay/ying_yong_gong_yao.txt
-----BEGIN PRIVATE KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5X3ezQUT2Cg5ujqoz+dfEBTGzavJRxG8CsXMzs5ualReWI0i3Itn15rG9mqYQUqIsfte2gAHc3+rNgMR8oEjcVrgY0qcPl/D3rj+/h0vYHl7lT5g93+n7/CVlk9KOhCm217kFV3gAJYusIXk6jWtpFXl2nXq1BlNhDgrBli4dozJ2k99OSUfNndrpuGfAVIOGIG4dsff598k+gb92eXwT151DMrqoV++387vRRnNnnBqbnYldBodBJXNyEsUCaf+CtacJy72tL6IwRVErD2MVuGjMWQ25Y1qWa/kNXI6ElIDljZylpWFDfMySMFkyOQra3RePlda7pDeKLmPwbwHpQIDAQAB
-----END PRIVATE KEY-----

  • 應(yīng)用私有(設(shè)置自己應(yīng)用的私有) alipay/ying_yong_si_yao.txt
-----BEGIN PRIVATE KEY-----
MIIEpQIBAAKCAQEA5X3ezQUT2Cg5ujqoz+dfEBTGzavJRxG8CsXMzs5ualReWI0i3Itn15rG9mqYQUqIsfte2gAHc3+rNgMR8oEjcVrgY0qcPl/D3rj+/h0vYHl7lT5g93+n7/CVlk9KOhCm217kFV3gAJYusIXk6jWtpFXl2nXq1BlNhDgrBli4dozJ2k99OSUfNndrpuGfAVIOGIG4dsff598k+gb92eXwT151DMrqoV++387vRRnNnnBqbnYldBodBJXNyEsUCaf+CtacJy72tL6IwRVErD2MVuGjMWQ25Y1qWa/kNXI6ElIDljZylpWFDfMySMFkyOQra3RePlda7pDeKLmPwbwHpQIDAQABAoIBAQDIh24SE+e9L5kRw4QS9we4E4+L1BnywepgN2q5IuSUgNhX5CucLywz14kXdRlJpAlCDHZbYz8fi2Vdst0R3AnOWSxNVrqkPiX3DguynGnzkPON+43bdm6WWNE9IFep2TcT5RzEFt1PZeuyT60xgmoSeQR6GiNx5hI4AKSHzSqSWteL9xd/IUbHrA4YBXhX/oqJdrQr7Ri+380qoHHLiz5gNkXzVGFKrqVwsvVOBGdQ75S+wSTmJJ6hYm9vF4T7FQk8Ar22/22ZFuNLa1IMDXEe8Oh5NVCoXQqMFyhAYf7oN4AzZrBSvLmd85wfQSmvbthmL2JdOynEytYVa7Q2F3zZAoGBAPp6RDO16jEZySrX4T/eKukCD1Cq2g1LAPsq8dxjfdSgNxtz9qt24vuflZu2RbW/VoLZxDZJEIGhY7x0ClhioEwixBCHuPcXLFRd4mvxawzpJBRg9z0Mquf1cret6CBqsML+hgqlu2WwAbgX6hJ3ZJ8Sz3zICoG3K1NgzQkAbsybAoGBAOqNJ/r56jtB42XeGrNRE9bmpOnNDMN56oKiGDIMMe/FDjwYJw/dX7Ih3k0AAGgQWgdq03s+6ji3sI65mcqUrwBf6gSufDWrOvolbKIIfiC1dn/h81HsfkC5y02hTjfmfYg/nCXF5WUsVahrYRgTZL6iHrav2EighyxZCHDlWiC/AoGBAKdkiqvcSTSjPPOq7lgWi6rIu593bt4vX+p7WsOkofU1VV69cv5IJ41tqzgy6gd6ZcBw9FYrIiLfzp2lFzzWPLZlDY7WhWBsVi3TyHvHDXnFXV1ZKCHek2ENgasLR/RSGOtX2hDHjaN5qsxy/vV0YQSGN6/2qD7kQMoqCRyY83M9AoGBAJrvUViVG2e3V1nkBCktRnivdIJIg8TgVMuj/W2Z5qamuYdywOLW7a7CdpDQjnQvUPkTVM1VuuxqUoOFEJTj8FHECda716qwCE5SyFakW4SJudQx0kPsf12MHUKTahK8+3Ez65Z8CdLyHUcaX1HDBcpzVuyAbdNTzta5nTzOE+ILAoGAF0dMOdqnprsr82MudHqjIZMSanfd+QHgARNT0IQVxIFBIsV4PkGmHKU2EZdcB604mZYqAKaCJy+LZIE6VGpgGydRZ98RSK/jaNprge5cm9KPy9nGdfVKBhPkrU3Lkcix0gcvRWC3HVVaYMiZlS1i1tpwgI8z0xtoA9EoLJGxuYc=
-----END PRIVATE KEY-----

  • 支付寶公鑰(設(shè)置自己申請支付寶公鑰) alipay/zhi_fu_bao_gong_yao.txt
-----BEGIN PRIVATE KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtaQiWU7tUcDzqbTT5cWF6PS9jn6sMlpG4wR1YFhUo8TDqW1FI5wi/dfylOqJSS2lV8OOuzMk80Ajq9wbyQ0oB+dmrgcZIwF8bLkHvGyO83SAmmNmZ8bcnlD91EnS2c+vIF02ADpE/NKaX+5gjXj9FMTr5z6cqrpfjxWYB7FCp77fd1hd6TbzkMaW70RzBkWGTVMG91p7uZexVKkURPl5Sb8KRnXSmTkjTTWBFZOsARFVu7nsbMjd+q3RYni3BvhfKyZIW/PtQ9HUrX3tHbGThdj2D4qgO3mWB51IdH0gM9OOTyFYvm9TMJGeJ6KdeELlGLNVGhRAbK4NJjPlnuVd2wIDAQAB
-----END PRIVATE KEY-----

  • 支付接口
# 定義資源
class Pay(Resource):
    def post(self):
        # 獲取訂單號,根據(jù)訂單生成 支付訂單
        # 支付訂單包括: 訂單號、支付金額、訂單名稱

        # 傳遞參數(shù)執(zhí)行支付類里的direct_pay方法,返回簽名后的支付參數(shù),
        url = alipay.direct_pay(
            subject="測試訂單",  # 訂單名稱
            # 訂單號生成,一般是當(dāng)前時間(精確到秒)+用戶ID+隨機(jī)數(shù)
            out_trade_no="201810021221",  # 訂單號
            total_amount=100,  # 支付金額
            return_url="http://112.74.55.3/result/"  # 支付成功后,跳轉(zhuǎn)url 【客戶端顯示】
        )

        # 將前面后的支付參數(shù),拼接到支付網(wǎng)關(guān)
        # 注意:下面支付網(wǎng)關(guān)是沙箱環(huán)境,最終進(jìn)行簽名后組合成支付寶的url請求
        re_url = "https://openapi.alipaydev.com/gateway.do?{data}".format(data=url)

        # 返回的是支付寶的支付地址
        return {'re_url': re_url}

# 添加資源
api.add_resource(Pay, '/paytest/')  # 支付接口

支付賬號密碼在沙盒賬號中,買家賬號: gpeggv3096@sandbox.com, 登錄密碼: 111111, 支付密碼: 111111

  • 支付成功跳轉(zhuǎn)的路由(客戶端顯示)
@blue.route('/result/')
def result():
    # 訂單支付完成,跳轉(zhuǎn)到對應(yīng)的頁面

    return render_template('cart.html')

# 支付寶返回的數(shù)據(jù)
data = {
    'seller_id': '2088102176233911',
    'trade_no': '2018101822001438720500654194', # 訂單號
    'timestamp': '2018-10-18 00:12:54',
    'app_id': '2016091800542542',
    'version': '1.0',
    'sign_type': 'RSA2',
    'out_trade_no': 'Thu Oct 18 00:09:45 20187265',
    'auth_app_id': '2016091800542542',
    'total_amount': '123.00',
    'charset': 'utf-8',
    'method': 'alipay.trade.page.pay.return'
    'sign': 'cjok55ELAfbGc9RfwsS93pplaFNUIv0hAsfzbklDU+5sdnq0lc9K1a+IRO8MJZpwCX9OjBLXqY64LEa2cM5hv0bly2HnEmbNTta8e15VdvXFH//zMWT05HeNmXu2+H3Kq2RzQbFs2LIdFD2HmYDnbkwhTyAxnhQWEn7yZdAeD/7vNjGoREW2Xbh3aV5ukSFBihzwTGJNMNxyKei6KxQwJRJKDyV0fdZyH6i39xoyp8aMfQGZqRC9HbKKBW6BsFg/At1hVsMJQ4Ib/6jK2NMNMckUIf1gXLrY4Gv/LaqVSYuZpwNQoEwgHYHiC9KUa0BhsgAlJDEpARliLnvyUUOJKA=='
}

  • 支付成功通知接口(支付寶通知服務(wù)器)
# 定義資源
class Paynotify(Resource):  # 異步支付通知
    def post(self):
        # 獲取 支付成功的 訂單號
        # 修改訂單狀態(tài)以及其他操作

        # 返回支付寶success,否則會不間斷的調(diào)用該回調(diào)
        return {'msg':'success'}

# 添加資源
api.add_resource(Paynotify, '/notify/') # 支付成功后的回調(diào)

# 支付寶返回的數(shù)據(jù)
data = {
     "subject": "測試訂單",
     "gmt_payment": "2016-11-16 11:42:19",
     "charset": "utf-8",
     "seller_id": "xxxx",
     "trade_status": "TRADE_SUCCESS",
     "buyer_id": "xxxx",
     "auth_app_id": "xxxx",
     "buyer_pay_amount": "0.01",
     "version": "1.0",
     "gmt_create": "2016-11-16 11:42:18",
     "trade_no": "xxxx",    # 訂單號
     "fund_bill_list": "[{\"amount\":\"0.01\",\"fundChannel\":\"ALIPAYACCOUNT\"}]",
     "app_id": "xxxx",
     "notify_time": "2016-11-16 11:42:19",
     "point_amount": "0.00",
     "total_amount": "0.01",
     "notify_type": "trade_status_sync",
     "out_trade_no": "xxxx",
     "buyer_logon_id": "xxxx",
     "notify_id": "xxxx",
     "seller_email": "xxxx",
     "receipt_amount": "0.01",
     "invoice_amount": "0.01",
     "sign": "xxx"
}

支付寶API文檔(通知參數(shù)說明): https://docs.open.alipay.com/204/105301/

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

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

  • 一、登錄螞蟻金服網(wǎng)站 二、配置沙箱應(yīng)用環(huán)境 進(jìn)入到沙盒環(huán)境[圖片上傳失敗...(image-ef475a-1540...
    王梓懿_1fbc閱讀 886評論 0 0
  • 一、登錄螞蟻金服網(wǎng)站 二、配置沙箱應(yīng)用環(huán)境 進(jìn)入到沙盒環(huán)境選擇沙箱應(yīng)用.png 沙箱應(yīng)用: 支付寶給開發(fā)者提供的調(diào)...
    鄭元吉閱讀 396評論 0 0
  • 一、登錄螞蟻金服網(wǎng)站 二、配置沙箱應(yīng)用環(huán)境 進(jìn)入到沙盒環(huán)境選擇沙盒應(yīng)用 沙箱應(yīng)用: 支付寶給開發(fā)者提供的調(diào)試環(huán)境應(yīng)...
    EndEvent閱讀 3,339評論 5 8
  • 一、登錄螞蟻金服網(wǎng)站 二、配置沙箱應(yīng)用環(huán)境 進(jìn)入到沙盒環(huán)境選擇沙河應(yīng)用 沙箱應(yīng)用: 支付寶給開發(fā)者提供的調(diào)試環(huán)境應(yīng)...
    不會忘的名字閱讀 493評論 0 0

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