zoukankan      html  css  js  c++  java
  • 微信支付 python版

    需求:

    微信打开商品列表页面-> 点击商品后直接显示付款页面-> 点击付款调用微信支付

    说明

    微信支付需要你申请了公众号(appid, key - 用于签名), 商户号(mch_id, AppSecret - 用于获取openid, 获取code)
    调起微信支付的页面需要配置授权, 如你的页面是http://www.shazuihuo.com/goods/index.html. 那么你需要配置为: http://www.shazuihuo.com/goods/ 即可, 这个是在公众号中配置

    签名算法和校验工具

    1. 签名校验通过时还是提示签名错误, 可能时候商户号KEY配置的问题了, 重置一下KEY, 你可以继续使用原来的KEY来重置
    2. 公众号变更时记得修改后台和前台代码中的APPID

    需要的ID和KEY

    # 微信配置基础数据
    WPC = {
        'APPID': 'wx53c1xxxxad626eb8',
        'APPSECRET': 'fdd177a7xxxxxxxxxxxxx856eeeb187c',
        'MCHID': '14222000000',
        'KEY': 'd7810713e1exxxxxxxxxxadc9617d0a6',
        'GOODDESC': '商户号中的公司简称或全称-无要求的商品名字',
        'NOTIFY_URL': 'https://www.xxxx.com/service/applesson/wechatordernotice', 
    }
    

    流程简介

    1. 网页内调起微信支付需要一个微信统一下单生成的订单号(prepay_id)
    2. 调用微信的统一下单接口需要一个用户在商户下的唯一标示(openid)
    3. 获取openid需要code参数加上AppID和AppSecret等,通过API换取access_token(openid)
    4. 其中code又需要通过页面跳转来获取, 需要appid和重定向url(可以带有你自己的参数, 会原样返回)
      那么开发思路便是一步步回朔了.

    1. 获取code

    用户点击按钮跳转到微信授权页, 微信处理完后重定向到redirect_uri, 并给我们加上code=xxx的参数, 这个code就是我们需要的

        $('#buy').click(function() {
            var param = {
                appid: 'wx53c1xxxxad626eb8',
                redirect_uri: 'https://www.xxxxx.com/wcpay/pay.html',
                response_type: 'code',
                scope: 'snsapi_base',
                state: '1'
            }
            window.location.href = 'https://open.weixin.qq.com/connect/oauth2/authorize?' + $.param(param);
        })
    

    2. 获取openid

    这个在后台完成, WPC中配置了你的APPSECRET, 这个不能泄露, 接口调用成功会拿到一个openid, 这里都不会有什么问题

        @classmethod
        def getOpenID(cls, kwargs):
            param = {
                'code': kwargs['code'],
                'appid': WPC['APPID'],
                'secret': WPC['APPSECRET'],
                'grant_type': 'authorization_code',
            }
    
            # 通过code获取access_token
            openIdUrl = 'https://api.weixin.qq.com/sns/oauth2/access_token'
            resp = requests.get(openIdUrl, params=param)
            # {openid, accss_token, refresh_token, openid, scope, expires_in}
            # openId = json.loads(resp.text)['openid']
            return resp.text
    

    3. 微信统一下单

    统一下单 时参数传递需要签名(微信用我们设定的密匙对参数进行MD5加密, 通过双方的签名判断请求是否被篡改)
    签名算法

    @classmethod
    def getSign(cls, kwargs):
    
        # 计算签名
        keys, paras = sorted(kwargs), []
        paras = ['{}={}'.format(key, kwargs[key]) for key in keys if key != 'appkey']  # and kwargs[key] != '']
        stringA = '&'.join(paras)
    
        stringSignTemp = stringA + '&key=' + WPC['KEY']
        sign = MD5(stringSignTemp).upper()
    
        return sign
    

    MD5函数

    import hashlib
    
    # 获取MD5
    def MD5(str):
        md5 = hashlib.md5()
        md5.update(str.encode('utf-8'))
        return md5.hexdigest()
    
    

    参数转xml

    @classmethod
    def getxml(cls, kwargs):
        
        kwargs['sign'] = Utility.getSign(kwargs)
    
        # 生成xml
        xml = ''
        for key, value in kwargs.items():
            xml += '<{0}>{1}</{0}>'.format(key, value)
        xml = '<xml>{0}</xml>'.format(xml)
    
        # print(xml)
        return xml
    

    统一下单代码

    code = self.POST.get('code')
    openidresp = Utility.getOpenID({'code': code})
    openid = json.loads(openidresp).get('openid')
    
    UnifieOrderRequest = {
        'appid': 'wx53c1xxxxad626eb8',  # 公众账号ID
        'body': '公司名称-商品',  # 商品描述
        'mch_id': '1397xxxxxx8',  # 商户号:深圳市泽慧文化传播有限公司
        'nonce_str': '',  # 随机字符串
        'notify_url': 'https://service.xxxx.com/service/applesson/wechatordernotice',  # 微信支付结果异步通知地址
        'openid': '',  # trade_type为JSAPI时,openid为必填参数!此参数为微信用户在商户对应appid下的唯一标识, 统一支付接口中,缺少必填参数openid!
        'out_trade_no': '',  # 商户订单号
        'spbill_create_ip': '',  # 终端IP
        'total_fee': '',  # 标价金额
        'trade_type': 'JSAPI',  # 交易类型
    }
    UnifieOrderRequest['nonce_str'] = Utility.getnoncestr()
    UnifieOrderRequest['openid'] = openid
    UnifieOrderRequest['out_trade_no'] = UnifieOrderRequest['mch_id'] + str(order.id)  # 内部订单号码
    UnifieOrderRequest['spbill_create_ip'] = self.request.remote_ip
    UnifieOrderRequest['total_fee'] = int(lesson.price * 100)
    # 签名并生成xml
    xml = Utility.getxml(UnifieOrderRequest)
    
    resp = requests.post("https://api.mch.weixin.qq.com/pay/unifiedorder", data=xml.encode('utf-8'), headers={'Content-Type': 'text/xml'})
    msg = resp.text.encode('ISO-8859-1').decode('utf-8')
    xmlresp = xmltodict.parse(msg)
    prepay_id = ''
    
    if xmlresp['xml']['return_code'] == 'SUCCESS':
        if xmlresp['xml']['result_code'] == 'SUCCESS':
            prepay_id = xmlresp['xml']['prepay_id']
            timestamp = str(int(time.time()))
            data = {
                "appId": xmlresp['xml']['appid'],
                "nonceStr": Utility.getnoncestr(),
                "package": "prepay_id=" + xmlresp['xml']['prepay_id'],
                "signType": "MD5",
                "timeStamp": timestamp
            }
            data['paySign'] = Utility.getSign(data)
            data['orderid'] = order.id  # 付款后操作的订单
            # 签名后返回给前端做支付参数
            return JsonResponse(self, '000', data=data)
        else:
            msg = xmlresp['xml']['err_code_des']
            return JsonResponse(self, '002', msg=msg)
    else:
        msg = xmlresp['xml']['return_msg']
        return JsonResponse(self, '002', msg=msg)
    

    统一下单成功返回后直接调用微信支付, 显示支付界面, 其中的paySign是我们自己的签名

    try {
        // statements
        // 微信统一订单, 返回预支付信息
        var code = query('code'),
            origin = query('groupid');
            // alert(code);
    
            $.post({
                url: orderurl,
                data: {
                    origin: origin,
                    mobile: phone,
                    code: code
                }
            }).then(function(resp) {
                if (resp.code && resp.code == "000") {
                    // 后台返回订单信息
                    var wepaydata = {
                        appId: resp.data.appId,
                        nonceStr: resp.data.nonceStr,
                        package: resp.data.package,
                        paySign: resp.data.paySign,
                        signType: "MD5",
                        timeStamp: resp.data.timeStamp
                    };
                    var orderid = resp.data.orderid || 0;
    
                    window.jsApiCall = function() {
                        WeixinJSBridge.invoke(
                            'getBrandWCPayRequest',
                            wepaydata,
                            function(res) {
                                WeixinJSBridge.log(res.err_msg);
                                // alert(res.err_code + res.err_desc + res.err_msg);
                                // alert(res.err_msg)
                                if (res.err_msg == 'get_brand_wcpay_request:ok') {
                                    $.get(orderurl, { orderid: orderid }, function(resp) {
                                        if (resp.code == '000') {
                                            window.location.href = window.location.href.replace('pay.html', 'success.html');
                                        } else {
                                            alert(resp.msg);
                                            // 一个code只能请求一次, 重新进入index
                                            if (resp.code == '002') {
                                                window.location.href = window.location.href.replace('pay.html', 'index.html');
                                            }
                                        }
                                    });
                                } else {
                                    // 其他支付异常微信有显示消息
                                    // alert(res.err_msg);
                                }
                            }
                        );
                    }
    
                    window.callpay = function() {
                        if (typeof WeixinJSBridge == "undefined") {
                            if (document.addEventListener) {
                                document.addEventListener('WeixinJSBridgeReady', jsApiCall, false);
                            } else if (document.attachEvent) {
                                document.attachEvent('WeixinJSBridgeReady', jsApiCall);
                                document.attachEvent('onWeixinJSBridgeReady', jsApiCall);
                            }
                        } else {
                            jsApiCall();
                        }
    
                    }
    
                    // 发起支付
                    window.callpay();
    
                } else {
                    alert(resp.msg);
                    // alert(JSON.stringify(resp) + resp.msg);
                }
            }, function(resp) {
                alert(resp)
                alert(JSON.stringify(resp))
    
                // alert('请求失败, 请重试');
            });
    } catch (e) {
        // statements
        alert(e)
    }
    

    4. 订单查询

    订单查询 是为了确认我们的支付是成功的

    # 查询微信付款情况
    orderid = self.GET.get('orderid')
    orderquery = {
        'appid': WPC['APPID'],
        'mch_id': WPC['MCHID'],
        'nonce_str': Utility.getnoncestr(),
        'out_trade_no': WPC['MCHID'] + orderid
    }
    xml = Utility.getxml(orderquery)
    print(xml)
    
    resp = requests.post("https://api.mch.weixin.qq.com/pay/orderquery", data=xml.encode('utf-8'), headers={'Content-Type': 'text/xml'})
    msg = resp.text.encode('ISO-8859-1').decode('utf-8')
    xmlresp = xmltodict.parse(msg)
    print(xmlresp)
    
    orderPaid = 0
    if xmlresp['xml']['return_code'] == 'SUCCESS':
        if xmlresp['xml']['result_code'] == 'SUCCESS':
            if xmlresp['xml']['trade_state'] == 'SUCCESS':
                orderPaid = 1
            else:
                msg = xmlresp['xml']['trade_state_desc']
                return JsonResponse(self, '001', msg=smg)
        else:
            msg = xmlresp['xml']['err_code_des']
            return JsonResponse(self, '001', msg=msg)
    else:
        msg = xmlresp['xml']['return_msg']
        return JsonResponse(self, '001', msg=msg)
    

    官方Demo

    SDK与DEMO下载, 用python就需要自己码代码, 当时看的是PHP的

  • 相关阅读:
    【WebGoat笔记】 CrossSite Scripting(XSS)
    SQL注入测试工具:Pangolin(穿山甲)
    SQL注入测试工具:Pangolin(穿山甲)
    js取两日期差,包含周六周日?
    CrossSite Scripting(XSS): 跨站脚本攻击介绍
    apmserv虚拟主机不能用set_time_limit(0);
    名称 不是有效的标识符 sql
    最佳的75个安全测试工具
    fzu 1686(DLX 重复点覆盖)
    hdu 3529(DLX)
  • 原文地址:https://www.cnblogs.com/wancy86/p/wcpay.html
Copyright © 2011-2022 走看看