1. 安装包
# 安装python-alipay-sdk
 # --upgrade 是你之前安装了pycrypto, 加它是升级, 一次都没安装的用户, 直接pip install python-alipay-sdk
 pip install python-alipay-sdk --upgrade
  1. 生成密钥文件
# openssl window上没有, linux下和mac上都带这个命令
 openssl
 OpenSSL> genrsa -out app_private_key.pem   2048  # 私钥
 OpenSSL> rsa -in app_private_key.pem -pubout -out app_public_key.pem # 导出公钥
 OpenSSL> exit
  1. 把支付宝公钥填写到沙箱环境
  2. python调用支付宝支付 python对接支付宝支付_python调用支付宝支付

  3. 把私钥放在项目里
  4. python调用支付宝支付 python对接支付宝支付_字符串_02

  5. 查看支付宝的公钥

python调用支付宝支付 python对接支付宝支付_字符串_03

  1. 把支付宝公钥复制粘贴到你项目的alipay_public_key.pem文件夹里, 记得在头加上
将-----BEGIN PUBLIC KEY-----添加到支付宝公钥的头部
将-----END PUBLIC KEY-----添加到支付宝的尾部
  1. 初始化
from alipay import AliPay
 alipay = AliPay(
     appid="",  # 沙箱appid 或 线上appid
     app_notify_url=None,  # 默认回调url  不写的话这里用None
     app_private_key_path="", # 私钥 
     alipay_public_key_path="", # 支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥,
     sign_type="RSA", # RSA 或者 RSA2
     debug=False  # 默认False   沙箱环境把这里设置为True
 )
  1. 根据对象发送请求
    5.1 电脑网站支付alipay.trade.page.pay
# 如果你是Python 2用户(考虑考虑升级到Python 3吧),请确保非ascii的字符串为utf8编码:
 subject = u"测试订单".encode("utf8")
 # 如果你是 Python 3的用户,使用默认的字符串即可
 subject = "测试订单"
 
 # 电脑网站支付,需要跳转到https://openapi.alipay.com/gateway.do? + order_string 这是线上环境
 # 电脑网站支付, 需要跳转到https://openapi.alipaydev.com/gateway.do? + order_string 这是沙箱环境
 order_string = alipay.api_alipay_trade_page_pay(
     out_trade_no="20161112",  # 订单编号
     total_amount="0.01",  # 总金额
     subject=subject,  # 订单标题 随便写个字符串
     return_url="https://example.com", # 返回的链接地址
     notify_url="https://example.com/notify" # 可选, 不填则使用默认notify url 不填这里写None
 )

5.2 手机网站支付 alipay.trade.wap.pay

# 手机网站支付,需要跳转到https://openapi.alipay.com/gateway.do? + order_string 这是线上环境
 # 手机网站支付, 需要跳转到https://openapi.alipaydev.com/gateway.do? + order_string 这是沙箱环境
 order_string = alipay.api_alipay_trade_wap_pay(
     out_trade_no="20161112",  # 订单编号
     total_amount="0.01",  # 总金额
     subject=subject,  # 订单标题 随便写个字符串
     return_url="https://example.com",  # 返回的链接地址
     notify_url="https://example.com/notify" # 可选, 不填则使用默认notify url  不填这里写None
 )

5.3 App支付 alipay.trade.app.pay

# App支付,将order_string返回给app即可
 order_string = alipay.api_alipay_trade_app_pay(
     out_trade_no="20161112",  # 订单id
     total_amount=0.01,  # 总金额
     subject=subject,  # 订单标题  随便写个字符串
     notify_url="https://example.com/notify" # 可选, 不填则使用默认notify url  不填这里写None
 )
  1. 基于flask的简单验证
from flask import Flask
 from flask import request
 app = Flask(__name__)
 
 @app.route('/', methods=["GET", "POST"])
 def hello_world():
     data = request.form.to_dict()
     # sign 不能参与签名验证
     signature = data.pop("sign")
 
     print(json.dumps(data))
     print(signature)
 
     # verify
     success = alipay.verify(data, signature)
     if success and data["trade_status"] in ("TRADE_SUCCESS", "TRADE_FINISHED" ):
         print("trade succeed")
  1. 列子
  1. 支付宝付款接口链接返回给前端
from . import api
 from ihome.models import Order
 from ihome.utils.commons import login_required
 from flask import g, current_app, jsonify
 from ihome.utils.response_code import RET
 from ihome import constants
 from alipay import AliPay
 import os
 
 @api.route("/orders/<int:order_id>/payment", methods=["POST"])
 @login_required
 def order_pay(order_id):
     """
     订单支付
     :param order_id: 订单的id
     :return: 支付宝支付的链接地址 格式json
     """
 
     # 接收用户id
     user_id = g.user_id
 
     # 校验参数
     # 根据order_id查询数据库, order_id是否存在, 订单是否属于该用户, 订单是否是待支付状态
     try:
         order = Order.query.filter(Order.id == order_id, Order.user_id == user_id, Order.status == "WAIT_PAYMENT").first()
     except Exception as e:
         current_app.logger.error(e)
         return jsonify(errnum=RET.DBERR, errmsg=u"获取订单信息失败")
 
     if order is None:
         return jsonify(errnum=RET.NODATA, errmsg=u"订单信息不存在")
 
     # 业务处理
     # 创建支付宝sdk的工具对象
     alipay_client = AliPay(
         appid="2016092500596768",  # 沙箱appid 或 线上appid
         app_notify_url=None,  # 默认回调url  不写的话这里用None
         # os.path.dirname(__file__): 获取当前文件所在目录的路径
         app_private_key_path=os.path.join(os.path.dirname(__file__), "keys/app_private_key.pem"),  # 私钥
         alipay_public_key_path=os.path.join(os.path.dirname(__file__), "keys/alipay_public_key.pem"),  # 支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥,
         sign_type="RSA2",  # RSA 或者 RSA2
         debug=False  # 默认False   沙箱环境把这里设置为True
     )
 
     # 手机网站支付,需要跳转到https://openapi.alipay.com/gateway.do? + order_string 这是线上环境
     # 手机网站支付, 需要跳转到https://openapi.alipaydev.com/gateway.do? + order_string 这是沙箱环境
     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="http://172.16.66.238:5000/orders.html",  # 返回的链接地址
         notify_url=None  # 可选, 不填则使用默认notify url  不填这里写None
     )
 
     # 构造让用户跳转的支付链接地址 这里用的是沙箱环境
     pay_url = constants.ALIPAY_URL_PREFIX + order_string
 
     # 返回应答
     return jsonify(errnum=RET.OK, errmsg=u"ok", data={"pay_url": pay_url})
  1. 前端回跳的参数
  2. python调用支付宝支付 python对接支付宝支付_支付宝_04


  3. python调用支付宝支付 python对接支付宝支付_字符串_05

  4. 验证是否是支付宝发送过来的
@api.route("/order/payment", methods=["PUT"])
 def save_order_payment_result():
     """保存订单支付结果"""
     # 接收参数
     # 将form表单数据转换成字典
     alipay_dict = request.form.to_dict()
 
     # 对支付宝的数据进行分离  提取出支付宝的签名参数sign 和剩下的其他数据
     alipay_sign = alipay_dict.pop("sign")
 
     # 业务处理
     # 创建支付宝sdk的工具对象
     alipay_client = AliPay(
         appid="2016092500596768",  # 沙箱appid 或 线上appid
         app_notify_url=None,  # 默认回调url  不写的话这里用None
         # os.path.dirname(__file__): 获取当前文件所在目录的路径
         app_private_key_path=os.path.join(os.path.dirname(__file__), "keys/app_private_key.pem"),  # 私钥
         alipay_public_key_path=os.path.join(os.path.dirname(__file__), "keys/alipay_public_key.pem"),
         # 支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥,
         sign_type="RSA2",  # RSA 或者 RSA2
         debug=False  # 默认False   沙箱环境把这里设置为True
     )
 
     # 借助工具验证参数的合法性
     # 如果确定参数是支付宝的, 返回True, 否则返回False
     result = alipay_client.verify(alipay_dict, alipay_sign)
 
     if result:
         # 获取订单id
         order_id = alipay_dict.get("out_trade_no")
 
         # 获取支付宝交易号
         trade_no = alipay_dict.get("trade_no")
 
         try:
         	 # 这里是根据订单id查询这个订单, 并且更新订单里的status和trade_no着两个字段
             Order.query.filter_by(id=order_id).update({"status": "WAIT_COMMENT", "trade_no": trade_no})
             # 保存到数据库中
             db.session.commit()
         except Exception as e:
         	# 有异常记录log日志
             current_app.logger.error(e)
             # 回滚到提交前
             db.session.commit()
 
     # 返回应答
     return jsonify(errnum=RET.OK, errmsg=u"ok")
  1. 线上环境就是把沙箱的appid换成线上的appid, 访问的域名用线上的域名.