flask支付宝支付

1.接入平台链接

2.扫码登录

3.支付宝开发文档

4.查看开发文档,有各种支付方式文档,这里用到手机网站支付

5.到开发者中心/网页/&移动应用/应用列表,填写应用基础信息,应一个账号管理不同的产品,创建网页&移动应用,使用场景:自用型应用,应用名字ihome_py_li,还可以添加功能

6.需要签约

7.配置环境,支付宝告诉我们,应用网关:支付宝将交易结果发生给服务器的接口,授权回调地址:用户支付完后,跳转回来商户网站的网址

8.接口加签方式:给支付宝数据,支付宝回馈数据都需要加密

9.提交审核

对于开发者的沙箱模式:开发者中心->研发服务->沙箱应用->信息配置

快速接入,下载服务端SKD,没有Python版的,怎么调用接口

    点击:去支付(订单编号),发起支付请求,发给商户系统(flask程序),flask生成订单信息并构造支付请求(订单编号、订单金额、return_url跳转:页面返回支付结果,是用户浏览器发起的请求、notify_url通知:是支付宝发起的请求,用来接收支付宝发送过来的消息),再发送给支付宝请求(HTTP请求方式),支付宝返回支付宝的支付链接地址给flask,flask再给用户,引导用户进入支付宝链接,用户输入支付密码,确认支付,直接发给支付宝,那么flask如何获取支付结果(return_url, notify_url),flask对返回的数据进行处理,给用户展示订单信息

    另外,flask可以发起查询请求,支付宝会返回支付状态,flask可以请求关闭订单(用户自定义发起的请求),支付宝返回处理结果。

开发文档->手机网站支付->公共参数->请求地址:公共请求参数:app_id, method,format,return_url,charset,sign_type,sign(签名),timestamp,version,notify_url,biz_content.请求参数:body,subject,......

rsa私钥 -> sign,rsa公钥 -> signature,两个值对比,是否为假冒的请求,

对于Python有写的工具包:pip install python-alipay

正式开放,公司与支付宝需要签订协议,这里用沙箱模式,

支付宝生成rsa密钥:

flask 发送私钥用来加密,想让谁解密,就将公钥给谁

flask利用rsa私钥加密相关参数,得到一个值sign,再将sign与参数一起打包,向支付宝发送,支付宝剔除sign,采用rsa的公钥对加密相关参数据,得到一个值signature,与sign比对,

Python使用支付宝的包:

https://github.com/fzlee/alipay/blob/master/README.zh-hans.md

# 1.3.0升级上来的用户, 请先卸载pycrypto:

pip uninstall pycrypto

# 安装python-alipay-sdk

pip install python-alipay-sdk --upgrade

需要配置沙箱环境,先生成密钥

打开终端:openssl

先生存私钥:

genrsa -out app_private_key.pem 2048(生成私钥的复杂程度)如果之前就有,记得删除 

ls 查看

cat app_private_key.pem 查看

再生成公钥:

openssl 

rsa -in app_private_key.pem -pubout -out app_public_key.pem  ( -in是读入)

cat app_public_key.pem 查看

将内容复制到沙箱的应用公钥:信息配置->必看部分->RSA2(SHA256)密钥(推荐) 设置应用公钥   

在程序当中维护私钥,将私钥文件放到,api_1_0下keys文件夹

将支付宝公钥,保存到文件keys下alipay_public_key.pem 主要在其中加

-----BEGIN PUBLIC KEY-----

-----END PUBLIC KEY-----

将应用私钥,保存到文件keys下app_private_key.pem 

编写后端文件

#coding:utf-8

from . import api

import os

@api.route('/orders/<int:order_id>/payment', methods=['post'])    需要订单编号

@login_required    需要先登录

def generate_order_payment():

生成支付宝支付信息

# 校验参数

user_id = g.user_id

# 需要导入Order

try:

    order = Order.query.filter(Order.id==order_id, Order.user_id == user_id, Order.status='WAIT_PAYMENT').first()    主要是过滤,看订单表是否在,状态是否正常,未被取消

    # 导入current_app, jsonify

except Exception as e:

    current_app.logger.error(e)

    return jsonify(errno=RET.DBERR, errmsg='获取订单信息有误')

if order is None:

    return jsonify(errno=RET.NODATA, errmsg='订单状态有误')

# 创建Alipay的工具对象,注意需要导入

alipay = Alipay(

appid =current_app.config.get.('ALIPAY_APPID')    #在注册时拿到,要是在config.py中放置,可以直接取出

app_notify_url=None, # 默认支付宝通知URL

app_private_key_path=os.path.join(os.path.dirname(__file__),'keys/app_private_key.pem')    #os.path.join(os.path.dirname(__file__) 寻找单签文件所在的目录

alipay_public_key_string=os.path.join(os.path.dirname(__file__), "keys/alipay_public_key.pem"),  # 支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥,

sign_type="RSA",  # RSA 或者 RSA2

debug=True  # 默认False

)

# 向手机发起手机网站支付的请求

# 手机网站支付

order_string= alipay_client.api_alipay_trade_wap_pay(

out_trade_no=order_id,    # 订单编号

total_amount = str(order.amount/100.0),    # 订单总金额

subject =u'爱家租房-%s' % order_id, # 展示给用户的订单信息

return_url = 'https://127.0.0.1:5000/orders.html' # 支付完后,浏览器跳转回的路径

notify_url = '' # 可选,不填就使用默认notify_url

)

current_app.config.get('ALIPAY_URL') = 'https://openapi.alipaydev.com/gateway.do'

alipay_url =current_app.config.get('ALIPAY_URL') + order_string # 从配置文件中获取

return jsonify(errno=RET.OK, errmsg='OK', data={'alipay_url': alipay_url})

2 .前端部分

$.get("/api/v1_0/user/orders?role=custom", function(resp){
        if (resp.errno == 0) {
            $(".orders-list").html(template("orders-list-tmpl", {orders:resp.data.orders}));
            // 发起支付请求
            $(".order-pay").on("click", function () {
                var orderId = $(this).parents("li").attr("order-id");
                $.ajax({
                    url: "/api/v1_0/orders/" + orderId + "/payment",
                    type: "post",
                    dataType: "json",
                    headers: {
                        "X-CSRFToken": getCookie("csrf_token"),
                    },
                    success: function (resp) {
                        if (resp.errno == 4101) {
                            location.href = "/login.html";
                        } else if (resp.errno == 0) {
                            // 从后端拿到了支付宝的链接,让用户跳转到支付宝的页面
                            location.href = resp.data.alipay_url;
                        }
                    }
                });
            });
    });

如果直接跳转回支付界面,后端拿不到支付结果,所有需要新建payComplete.html,先跳转到这个界面

改return_url = 'https://127.0.0.1:5000/payComplete.html' # 支付完后,浏览器跳转回的路径

后端需要拿到支付结果,在页面payComplete.html中点击跳转时再将支付结果结果返回给后端

新建payComplete.html

嵌入脚本,向pay.py中新的视图函数发起ajax请求

<script type="text/javascript">

// 将支付宝的参数转发给后端接口,注意从url中拿数据的方法

//  # 前端怎么从URL中获取参数,document.location.search,有问号,去除问号,.substr(1)

function getCookie(name) {
            var r = document.cookie.match("\\b" + name + "=([^;]*)\\b");
            return r ? r[1] : undefined;
        }

var  params=documents.location.search.substr(1);

// 注意这个请求是加载完页面以后就直接发起的

跳转在页面的<a class="btn btn-success" href="/orders.html">返回我的订单</a> 中

$.ajax({

    url:'/api/v1_0/payments',

    type:'post',

    data:params,

    headers:{

    'X-CSRFToken':getCookie('csrf_token')

    }

})

</script>

 在自己定义的页面中,将支付信息传到后端

@api.route('/payment', methods=['post'])
def save_payment_result():
    """保存支付宝支付结果"""
    payment_dict = request.form.to_dict()
    if not payment_dict:
        return jsonify(errno=RET.PARAMERR, errmsg='参数有误')
    # 构建支付宝工具对象
    alipay_client = AliPay(
        appid=current_app.config.get('ALIPAY_APPID'),
        app_notify_url=None,  # 默认支付宝通知的url
        app_private_key_string=os.path.join(os.path.dirname(__file__), 'keys/app_private_key.pem'),
        alipay_public_key_string=os.path.join(os.path.dirname(__file__), "keys/alipay_public_key.pem"),
        # 支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥,
        sign_type="RSA",  # RSA 或者 RSA2
        debug=True  # 默认False
    )
    
    # 用构建的支付宝对象验证发送过来的信息
    sign = payment_dict.pop('sign')
    # 判断参数是否是有支付宝构建的
    result = alipay_client.verify(payment_dict, sign)
    # 将从字典中弹出的sign, 与字典剩下的键值对比较,看sign是否是有字典剩下的键值对加密得到的
    # 如果返回true,表示校验成功,参数是有支付宝构造的,否则为假
    if result:
        order_id = payment_dict.get('out_trade_no')  # 我们自己的订单编号
        trade_no = payment_dict.get('trade_no')  # 支付宝的交易编号
        # 修改数据库的数据,变更订单状态
        try:
            Order.query.filter(id=order_id).update({'status':'WAIT_COMMENT', 'trade_no': trade_no})
            db.session.commit()
        except Exception as e:
            db.session.rollback()
            current_app.logger.error(e)
            return jsonify(errno=RET.DBERR, errmsg='记录支付结果异常')
    return jsonify(errno=RET.OK, errmsg='OK')

在订单表中,添加字段 

trade_no = db.column(db.string(128)) # 支付宝的交易编号

猜你喜欢

转载自blog.csdn.net/ernest_li_shun/article/details/80388051