web第三方支付

微信支付

github 支付客户端: https://github.com/zwczou/weixin-python

开发文档:https://pay.weixin.qq.com/wiki/doc/api/index.html

微信支付的企业付款到零钱开通:https://jingyan.baidu.com/article/fec7a1e5989fc01191b4e74e.html

微信支付-证书安装+使用+CentOS+Python+Tornado

版权声明:本文为CSDN博主「Victor.Zhang」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u013538542/article/details/99695955

使用微信支付的API证书下载

证书下载后,可以看到三个证书如图

 

 

 

 

 

在CentOS服务器上安装证书程序

教程:https://manuals.gfi.com/en/kerio/connect/content/server-configuration/ssl-certificates/adding-trusted-root-certificates-to-the-server-1605.html

在Linux上的CentOS 6安装ca-certificates包:

$ yum install ca-certificates

启用动态CA配置特性

$ update-ca-trust force-enable

把从微信商户平台下载的三个证书的其中两个(apiclient_cert.pem 和apiclient_key.pem)拷贝到这个目录下

$ /etc/pki/ca-trust/source/anchors/

从本地把证书拷贝到服务器上很简单的,使用scp命令就行

$ scp /User/victor/Desktop/apiclient_cert.pem root@你的服务器IP:/etc/pki/ca-trust/source/anchors/
$ scp /User/victor/Desktop/apiclient_key.pem root@你的服务器IP:/etc/pki/ca-trust/source/anchors/

Python的代码编写:企业付款到零钱

  # 请求接口
    general_url = "https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers" 
    # 服务端生产环境
    server_root_ca_filepath = "/etc/pki/tls/certs/ca-bundle.crt"  # 看文章底部解释
    cert_ca_filepath ='/etc/pki/ca-trust/source/anchors/apiclient_cert.pem'
    key_ca_filepath = '/etc/pki/ca-trust/source/anchors/apiclient_key.pem'
    # 本地测试环境
    # server_root_ca_filepath = "/Users/victor/Desktop/1535260341_20190816_cert/cacert.pem"
    # cert_ca_filepath = "/Users/victor/Desktop/1535260341_20190816_cert/apiclient_cert.pem"
    # key_ca_filepath = "/Users/victor/Desktop/1535260341_20190816_cert/apiclient_key.pem" 

    # https://stackoverflow.com/questions/23954120/using-certificates-in-urllib3
    # 重点关注这里!!!
    httpreq = urllib3.PoolManager(cert_reqs='CERT_REQUIRED',
                                cert_file=cert_ca_filepath, 
                                key_file=key_ca_filepath, 
                                ca_certs=server_root_ca_filepath)
    resp = httpreq.request("POST", general_url, headers={ 'Content-Type' : 'application/xml' }, body=xml_parameters.encode("utf-8"))
    resp_data = str(resp.data, encoding="utf-8")

 

证书配置错误时提示

{
    'return_code': 'SUCCESS', 
    'return_msg': '证书出错,请登录微信支付商户平台下载证书', 
    'mch_appid': 'wx54611105e8382140', 'mchid': '1535260341', 
    'result_code': 'FAIL', 
    'err_code': 'CA_ERROR', 
    'err_code_des': '证书出错,请登录微信支付商户平台下载证书'
}

证书配置正确,没有开通企业付款到零钱的功能时提示

{
    'return_code': 'SUCCESS', 
    'return_msg': 'NO_AUTH', 
    'mch_appid': 'wx54611105e8382140', 
    'mchid': '1535260341', 
    'result_code': 'FAIL', 
    'err_code': 'NO_AUTH', 
    'err_code_des': '产品权限验证失败,请查看您当前是否具有该产品的权限'
}

证书配置正确,已经开通企业付款到零钱的功能时提示:

该功能需要满足公众号90天,且最近30天连续有交易才能开通,所以,我在等

服务器根证书: /etc/pki/tls/certs/ca-bundle.crt 来自你在CentOS下安装完后就能找到这个目录了
本地的根证书来自:/Users/victor/Desktop/1535260341_20190816_cert/cacert.pem来自 https://curl.haxx.se/ca/cacert.pem
微信文档有解释,文档地址:https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=23_4


支付宝支付

二维码API

草料二维码: https://cli.im/

安装SDK

win10安装出错,查看错误日志,应该是pycrypto没有安装成功,Ubuntu18.04可以正常安装

pip install alipay-sdk-python

沙箱测试 

开放平台-->文档中心-->沙箱环境

 

 

 Demo

import logging
import traceback
import json
from . import globalSettings

from alipay.aop.api.AlipayClientConfig import AlipayClientConfig
from alipay.aop.api.DefaultAlipayClient import DefaultAlipayClient
from alipay.aop.api.request.AlipayTradeQueryRequest import AlipayTradeQueryRequest
from alipay.aop.api.request.AlipayTradeCloseRequest import AlipayTradeCloseRequest
from alipay.aop.api.request.AlipayTradeRefundRequest import AlipayTradeRefundRequest
from alipay.aop.api.request.AlipayTradeFastpayRefundQueryRequest import AlipayTradeFastpayRefundQueryRequest
from alipay.aop.api.request.AlipayDataDataserviceBillDownloadurlQueryRequest import AlipayDataDataserviceBillDownloadurlQueryRequest
from alipay.aop.api.request.AlipayTradeWapPayRequest import AlipayTradeWapPayRequest

from alipay.aop.api.response.AlipayTradePayResponse import AlipayTradePayResponse
from alipay.aop.api.response.AlipayTradeCloseResponse import AlipayTradeCloseResponse
from alipay.aop.api.response.AlipayTradeFastpayRefundQueryResponse import AlipayTradeFastpayRefundQueryResponse
from alipay.aop.api.response.AlipayDataDataserviceBillDownloadurlQueryResponse import AlipayDataDataserviceBillDownloadurlQueryResponse

from alipay.aop.api.domain.AlipayTradeCloseModel import AlipayTradeCloseModel
from alipay.aop.api.domain.AlipayTradeQueryModel import AlipayTradeQueryModel
from alipay.aop.api.domain.AlipayTradeWapPayModel import AlipayTradeWapPayModel
from alipay.aop.api.domain.AlipayTradeRefundModel import AlipayTradeRefundModel
from alipay.aop.api.domain.AlipayTradeFastpayRefundQueryModel import AlipayTradeFastpayRefundQueryModel
from alipay.aop.api.domain.AlipayDataDataserviceBillDownloadurlQueryModel import AlipayDataDataserviceBillDownloadurlQueryModel

logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s %(levelname)s %(message)s',
    filemode='a', )
logger = logging.getLogger('')


def get_alipay_client():
    """
    设置配置,包括支付宝网关地址、app_id、应用私钥、支付宝公钥等,其他配置值可以查看AlipayClientConfig的定义。
    """
    alipay_client_config = AlipayClientConfig()
    alipay_client_config.server_url = globalSettings.server_url  # 支付宝网关
    alipay_client_config.app_id = globalSettings.app_id  # 支付宝分配给开发者的应用ID
    alipay_client_config.app_private_key = globalSettings.app_private_key  # 应用私钥
    alipay_client_config.alipay_public_key = globalSettings.alipay_public_key  # 支付宝公钥
    """
    得到客户端对象。
    注意,一个alipay_client_config对象对应一个DefaultAlipayClient,定义DefaultAlipayClient对象后,alipay_client_config不得修改,如果想使用不同的配置,请定义不同的DefaultAlipayClient。
    logger参数用于打印日志,不传则不打印,建议传递。
    """
    client = DefaultAlipayClient(alipay_client_config=alipay_client_config, logger=logger)
    return client


default_alipay_client = get_alipay_client()


def get_alipay_page(out_trade_no, total_amount, subject, body=None, timeout_express=None, product_code="QUICK_WAP_PAY"):
    """
    功能:支付宝手机网站支付接口(alipay.trade.wap.pay)接口调试入口页面
    对于页面跳转类API,SDK不会也无法像系统调用类API一样自动请求支付宝并获得结果,而是在接受request请求对象后,
    为开发者生成前台页面请求需要的完整form表单的html(包含自动提交脚本),商户直接将这个表单的String输出到http response中即可。
    :param out_trade_no : 商户订单号,商户网站订单系统中唯一订单号,必填
    :param total_amount : 付款金额,必填
    :param subject : 订单名称,必填
    :param body : 超时时间 可空
    :param timeout_express : 超时时间 可空
    :param product_code : 销售产品码,商家和支付宝签约的产品码。该产品请填写固定值:QUICK_WAP_WAY,必填
    :return form:
    """
    model = AlipayTradeWapPayModel()
    model.out_trade_no = out_trade_no
    model.subject = subject
    model.total_amount = total_amount
    model.timeout_express = timeout_express
    model.body = body
    alipay_request = AlipayTradeWapPayRequest(biz_model=model)
    alipay_request.return_url = globalSettings.return_url
    alipay_request.notify_url = globalSettings.notify_url
    form = ""
    try:
        form = default_alipay_client.page_execute(alipay_request)
    except Exception as e:
        print(e)
    return form


def get_alipay_query(out_trade_no, trade_no):
    """
    交易查询接口
    :param out_trade_no: 商户订单号,商户网站订单系统中唯一订单号,必填
    :param trade_no: 支付宝交易号
    :return trade_no:  支付宝28位交易号
    :return out_trade_no:  支付时传入的商户订单号
    :return trade_status:  交易当前状态
    """
    model = AlipayTradeQueryModel()
    model.out_trade_no = out_trade_no
    model.trade_no = trade_no
    request = AlipayTradeQueryRequest(biz_model=model)  # 创建API对应的request类
    response = default_alipay_client.execute(request)
    print(response)
    return response


def alipay_refund(out_trade_no, trade_no, out_request_no, refund_amount):
    """
    交易退款接口,trade_no、out_trade_no如果同时存在优先取trade_no
    :param out_trade_no: 商户订单号,和支付宝交易号二选一
    :param trade_no: 支付宝交易号,和商户订单号二选一
    :param out_request_no: 本次退款请求流水号,部分退款时必传
    :param refund_amount: 退款金额,不能大于订单总金额
    :param refund_amount: 退款的原因说明
    :return refund_fee: 该笔交易已退款的总金额
    """
    model = AlipayTradeRefundModel()
    model.out_trade_no = out_trade_no
    model.trade_no = trade_no
    model.refund_amount = refund_amount
    model.refund_reason = refund_amount
    model.out_request_no = out_request_no
    request = AlipayTradeRefundRequest(biz_model=model)
    response = default_alipay_client.execute(request)
    print(response)
    return response


def alipay_refund_query(out_trade_no, trade_no, out_request_no):
    """
    交易退款查询接口
    商户订单号和支付宝交易号不能同时为空。 trade_no、  out_trade_no如果同时存在优先取trade_no
    :param out_trade_no: 商户订单号,和支付宝交易号二选一
    :param trade_no: 支付宝交易号,和商户订单号二选一
    :param out_request_no: 请求退款接口时,传入的退款请求号,如果在退款请求时未传入,则该值为创建交易时的外部交易号
    :return refund_fee: 该笔交易已退款的总金额
    """
    model = AlipayTradeFastpayRefundQueryModel()
    model.out_trade_no = out_trade_no
    model.trade_no = trade_no
    model.out_request_no = out_request_no
    alipay_request = AlipayTradeFastpayRefundQueryRequest(biz_model=model)
    response = default_alipay_client.execute(alipay_request)
    print(response)
    return response


def get_bill_downloadurl(bill_date, bill_type="trade"):
    """
    功能:支付宝手机网站alipay.data.dataservice.bill.downloadurl.query (查询对账单下载地址)接口调试入口页面
    :param bill_type: 固定传入trade
    :param bill_date: 需要下载的账单日期,最晚是当期日期的前一天
    :return bill_download_url:账单文件下载地址,30秒有效
    """
    model = AlipayDataDataserviceBillDownloadurlQueryModel()
    model.bill_type = bill_type
    model.bill_date = bill_date

    alipay_request = AlipayDataDataserviceBillDownloadurlQueryRequest(biz_model=model)
    return _execute_request(alipay_request, AlipayDataDataserviceBillDownloadurlQueryResponse())


def async_alipay_notify():
    """
    异步通知验签
    :return:
    """


def close_alipay_trade(out_trade_no, trade_no):
    """
    功能:支付宝手机网站alipay.trade.close (统一收单交易关闭接口)调试入口页面
    :param out_trade_no: 商户订单号,和支付宝交易号二选一
    :param trade_no: 支付宝交易号,和商户订单号二选一
    :return:
    """

    close_model = AlipayTradeCloseModel()
    close_model.out_trade_no = out_trade_no
    close_model.trade_no = trade_no
    alipay_request = AlipayTradeCloseRequest(biz_model=close_model)

    is_success, response = _execute_request(alipay_request, AlipayTradeCloseResponse())
    if is_success:
        # 如果业务成功,则通过respnse属性获取需要的值
        return {"success": True, "trade_no": response.trade_no, "out_trade_no": response.out_trade_no}
    else:
        return {"success": False, "msg": response}


def _execute_request(request, response):
    response_content = None
    try:
        response_content = default_alipay_client.execute(request)
    except Exception as e:
        print(traceback.format_exc())
    if not response_content:
        return False, "failed execute"
    else:
        # 解析响应结果
        response.parse_response_content(response_content)
        print(response.body)
        if response.is_success():
            # 如果业务成功,则通过respnse属性获取需要的值
            return True, response
        else:
            # 如果业务失败,则从错误码中可以得知错误情况,具体错误码信息可以查看接口文档
            print(response.code + "," + response.msg + "," + response.sub_code + "," + response.sub_msg)
            return False, "failed execute"


if __name__ == '__main__':
    get_bill_downloadurl(bill_date="2016-04-05")

手机网站支付产品

手机网站支付产品流程:https://docs.open.alipay.com/203/105288/

API接口调用流程:https://docs.open.alipay.com/203/105285/

安全分析:

API调用分析

步骤一:用户下单-->商户系统生成订单,生成并发送支付请求-->支付宝接收请求

存在商户系统(或黑客)修改订单的风险,如:用户本想支付1元,被修改为100元。

步骤二:支付宝生成订单进行确认,并对订单签名,让商户系统转交给用户--->商户系统接收form,转交给用户-->用户接收form

1、为了防止商户系统(或黑客等)修改订单,支付宝生成订单向用户确认。

2、为了防止确认订单在中途被修改,支付宝对订单进行签名

加密、解密、签名、验签介绍:https://www.cnblogs.com/pcheng/p/9629621.html

手机网站支付产品流程分析:

支付宝确认订单是一个自动提交的form表单,会尝试唤起支付宝APP,否则在一定的时间后会自动进入网页支付流程。

1、唤起APP后,用户确认订单,完成支付,支付宝通知商户系统

网页支付流程

DNS劫持:https://baike.baidu.com/item/DNS%E5%8A%AB%E6%8C%81

问题汇总 

pip3 install alipay-sdk-python

src/MD2.c:31:20: fatal error: Python.h: No such file or directory
compilation terminated.
error: command 'x86_64-linux-gnu-gcc' failed with exit status 1
----------------------------------------
ERROR: Failed building wheel for pycrypto

sudo apt-get install python3-dev

 

posted @ 2019-07-25 16:53  逐梦客!  阅读(1191)  评论(0)    收藏  举报