python 调用支付宝支付

支付宝接口集成,本地环境调试支付请求

1.首先登录 蚂蚁金服网站,也就是支付宝开发者平台

登录蚂蚁金服开发者平台后,创建沙箱应用

开发者平台

也就是支付宝给开发者提供的调试环境应用

沙箱环境:https://openhome.alipay.com/platform/appDaily.htm?tab=info


沙箱测试应用

2.我们设置应用公钥

设置公钥,访问https://docs.open.alipay.com/291/105971/ 这个网址

下载生成公钥的工具

生成密钥

下载解压后

签名工具

生成公钥


生成公钥

公钥生成后会得到两个文件


公钥文件

生成公钥后,将公钥填写到信息配置里


当我们填好公钥保存后,会自动给我们生成支付宝公钥


将生成的支付宝公钥,复制下载到一个TXT文件中


将3个密钥修改成英文或者拼音名称后,放到项目中


在秘钥txt文件里,秘钥内容的头部和结尾加上两行字符串,注意所有秘钥都要加


-----BEGIN PRIVATE KEY-----

秘钥内容....

-----END PRIVATE KEY----


···

#!/usr/bin/env python

# -*- coding:utf8 -*-

# pip install pycryptodome  需要模块加密方面的模块

__author__ = 'bobby'

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)

        # 将字典类型的数据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)

if __name__ == "__main__":

    """支付请求过程"""

    # 传递参数初始化支付类

    alipay = AliPay(

        appid="2016080800192023",                                  # 设置签约的appid

        app_notify_url="http://projectsedus.com/",                  # 异步支付通知url

        app_private_key_path=u"ying_yong_si_yao.txt",              # 设置应用私钥

        alipay_public_key_path="zhi_fu_bao_gong_yao.txt",          # 支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥,

        debug=True,  # 默认False,                                  # 设置是否是沙箱环境,True是沙箱环境

        return_url="http://47.92.87.172:8000/"                      # 同步支付通知url

    )

    # 传递参数执行支付类里的direct_pay方法,返回签名后的支付参数,

    url = alipay.direct_pay(

        subject="测试订单",                              # 订单名称

        # 订单号生成,一般是当前时间(精确到秒)+用户ID+随机数

        out_trade_no="201702021225",                    # 订单号

        total_amount=100,                              # 支付金额

        return_url="http://47.92.87.172:8000/"          # 支付成功后,跳转url

    )


    # 将前面后的支付参数,拼接到支付网关

    # 注意:下面支付网关是沙箱环境,

    re_url = "https://openapi.alipaydev.com/gateway.do?{data}".format(data=url)

    print(re_url)

    # 最终进行签名后组合成支付宝的url请求

···



密钥配置

4.生成支付URL后,我们用这个URL模拟支付一下

注意:沙箱环境,支付的时候要用沙箱账号里提供的支付账号才可以支付

支付成功后已经,跳转到我们设置的同步处理页面

5.支付宝支付成功后通知接口验证


'''

#!/usr/bin/env python

# -*- coding:utf8 -*-

# pip install pycryptodome  需要模块加密方面的模块

__author__ = 'bobby'

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)

        # 将字典类型的数据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)

if __name__ == "__main__":

    """支付宝支付成功后通知接口验证"""

    # 接收支付宝支付成功后,向我们设置的同步支付通知url,请求的参数

    return_url = 'http://47.92.87.172:8000/?total_amount=100.00&timestamp=2017-10-11+22%3A44%3A17&sign=dHW%2F25EDd%2BYKqkU5krhseDNIOEyDpdJzSAaoqhTC0nlv8%2FEmrQVd0WqgGK0CS8Pax8sK4jIOdGLFa6lQEbIfzvH3Na2W949yCAYX04JL1Bi02wog7a8L7vfW9Kj%2BjfTQxumGH%2B1Drbezdg9gKOx3tX0cb1yBBdfifK6l1%2BE5UjggGbY60F6SD8A8XI06NMWb4ViU%2FLYtBhwAwU2koy1IK2%2BtBJM1xYFuBRlcWF61xCxexHwO0WEA3AwVRW1miuJjOpGiBTOwPI9Huj0WhkyRebIjBhSxReJdZIdTfAgwj4oqo4jAJCHDa6DKBM0H3wjKKXSyMeMBGKQB0Uv2rNdyng%3D%3D&trade_no=2017101121001004320200174640&sign_type=RSA2&auth_app_id=2016080800192023&charset=utf-8&seller_id=2088102170418468&method=alipay.trade.page.pay.return&app_id=2016080800192023&out_trade_no=201702021227&version=1.0'

    # 将同步支付通知url,传到urlparse

    o = urlparse(return_url)

    # 获取到URL的各种参数

    query = parse_qs(o.query)

    # 定义一个字典来存放,循环获取到的URL参数

    processed_query = {}

    # 将URL参数里的sign字段拿出来

    ali_sign = query.pop("sign")[0]

    # 传递参数初始化支付类

    alipay = AliPay(

        appid="2016080800192023",                                  # 设置签约的appid

        app_notify_url="http://projectsedus.com/",                  # 异步支付通知url

        app_private_key_path=u"ying_yong_si_yao.txt",              # 设置应用私钥

        alipay_public_key_path="zhi_fu_bao_gong_yao.txt",          # 支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥,

        debug=True,  # 默认False,                                  # 设置是否是沙箱环境,True是沙箱环境

        return_url="http://47.92.87.172:8000/"                      # 同步支付通知url

    )

    # 循环出URL里的参数

    for key, value in query.items():

        # 将循环到的参数,以键值对形式追加到processed_query字典

        processed_query[key] = value[0]

    # 将循环组合的参数字典,以及拿出来的sign字段,传进支付类里的verify方法,返回验证合法性,返回布尔值,True为合法,表示支付确实成功了,这就是验证是否是伪造支付成功请求

    print(alipay.verify(processed_query, ali_sign))

# 如果别人伪造支付成功请求,它不知道我们的支付宝公钥,伪造的就无法通过验证,测试可以将支付宝公钥更改一下,在验证就会失败,别忘了改回来

'''


©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,219评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,363评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,933评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,020评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,400评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,640评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,896评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,597评论 0 199
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,327评论 1 244
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,581评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,072评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,399评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,054评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,083评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,849评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,672评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,585评论 2 270

推荐阅读更多精彩内容