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

    一  支付

    https://www.cnblogs.com/xiaoyuanqujing/protected/articles/11822104.html

    商户系统和微信支付系统主要交互:

    1、小程序内调用登录接口,获取到用户的openid,api参见公共api【小程序登录API

    2、商户server调用支付统一下单,api参见公共api【统一下单API

    3、商户server调用再次签名,api参见公共api【再次签名

    4、商户server接收支付通知,api参见公共api【支付结果通知API

    下面的代码具体怎么用代码实现,我们再这里不讲,再后面文档中书写,我们先整理整体的业务逻辑

    1小程序登入API解释

    再之前的文档中我们已经对小程序的登入做了说明我们不在重复,如果有不懂的,可以参考前面的博客,如果不懂,可以再博客底下留言,我会第一时间回答

    2统一下单接口解释

    ​ 1当用户发起下单请求,且用户是登入状态的情况下,我们就可以创建我们商城的订单了。

    ​ 2当订单创建完毕,我们应该发起支付,调用支付接口,也就是统一下单接口(这里的下单不是我们商城的下单,而是对微信官方进行支付下单),我们按照微信统一下单接口发送数据,微信下单接口会同步返回数据给我们,也就是上图中prepay_id

    3再次签名

    ​ 1当我们拿到统一下的那数据以后,我们要再次进行签名(对数据加密以及处理)。

    ​ 2 然后将数据发送给我们小程序。

    ​ 3 小程序拿到我们发送的数据后调起支付界面,这样用户就可以进行支付了,如果支付成功,微信会直接返回 结果给我们小程序

    4异步通知接口

    ​ 1在第三步再次签名中我们小程序已经知道用户是否支付成功,但是我们后端还不知道该订单是否支付成功

    ​ 2 基于1的问题,微信会以异步的方式通知我们后端程序,我们拿到微信异步通知的数据,我们就可以对订单 进行修改。那这样就实现了,前后都知道用户的支付结果。

    示例:

    1.前端

    2.后端

    2.1目录

     配置文件

    1.settings.py
    AppId="wx29fad388b1f51644"
    
    AppSecret="d00c23ad3faf96ca218c20f6aaece7a7"
    
    code2Session="https://api.weixin.qq.com/sns/jscode2session?appid={}&secret={}&js_code={}&grant_type=authorization_code"
    #商户号
    pay_mchid ='1415981402'
    
    pay_apikey = 'xi34nu5jn7x2uujd8u4jiijd2u5d6j8e'
    
    2.wx_login.py
    from app01.wx import settings
    import requests
    
    def login(code):
        response=requests.get(settings.code2Session.format(settings.AppId,settings.AppSecret,code))
        data=response.json()
        if data.get("openid"):
            return data
        else:
            return False
    
    3.wxbizdatacrypt.py
    import base64
    import json
    from Crypto.Cipher import AES
    from  app01.wx import settings
    
    class WXBizDataCrypt:
        def __init__(self, appId, sessionKey):
            self.appId = appId
            self.sessionKey = sessionKey
    
        def decrypt(self, encryptedData, iv):
            # base64 decode
            sessionKey = base64.b64decode(self.sessionKey)
            encryptedData = base64.b64decode(encryptedData)
            iv = base64.b64decode(iv)
    
            cipher = AES.new(sessionKey, AES.MODE_CBC, iv)
    
            decrypted = json.loads(self._unpad(cipher.decrypt(encryptedData)))
    
            if decrypted['watermark']['appid'] != self.appId:
                raise Exception('Invalid Buffer')
    
            return decrypted
    
        def _unpad(self, s):
            return s[:-ord(s[len(s)-1:])]
    
        @classmethod
        def getInfo(cls,encryptedData,iv,session_key):
    
            return cls(settings.AppId,session_key).decrypt(encryptedData, iv)

    cbv

    from rest_framework.views import  APIView
    from  rest_framework.response import  Response
    from app01.wx import wx_login
    from django.core.cache import cache
    import hashlib,time
    import random
    from app01.wx import settings
    import requests
    class Pay(APIView):
        def post(self,request):
            param=request.data
            if param.get("login_key"):
                #缓存获取openid和session_key
                openid,session_key=cache.get(param.get("login_key")).split("&")
                self.openid=openid
                #如果是Nginx做的负载就要HTTP_X_FORWARDED_FOR
                if request.META.get('HTTP_X_FORWARDED_FOR'):
                    self.ip =request.META['HTTP_X_FORWARDED_FOR']
                else:
                    #如果没有用Nginx就用REMOTE_ADDR
                    self.ip = request.META['REMOTE_ADDR']
                #调用自定义pay函数
                data = self.pay()
                return Response({"code":200,"msg":"ok","data":data})
            else:
                return Response({"code":200,"msg":"缺少参数"})
    
        #获取随机字符串函数(根据业务场景来)
        def get_str(self):
            str_all="1234567890abcdefghjklmasdwery"
            nonce_str="".join(random.sample(str_all,20))
            return nonce_str
    
        #获取订单号(根据实际场景来)
        def get_order(self):
            order_id=str(time.strftime("%Y%m%d%H%M%S"))
            return order_id
    
        #
        def xml_to_dict(self,data):
            import xml.etree.ElementTree as ET
            xml_dict={}
            data_dic=ET.fromstring(data)
            for item in data_dic:
                xml_dict[item.tag]=item.text
            return  xml_dict
    
       #签名
        def get_sign(self):
            data_dic = {
                "nonce_str": self.nonce_str,
                "out_trade_no": self.out_trade_no,
                "spbill_create_ip": self.ip,
                "notify_url": self.notify_url,
                "openid": self.openid,
                "body": self.body,
                "trade_type": "JSAPI",
                "appid": self.appid,
                "total_fee": self.total_fee,
                "mch_id": self.mch_id
            }
            sign_str = "&".join([f"{k}={data_dic[k]}" for k in sorted(data_dic)])
            sign_str = f"{sign_str}&key={settings.pay_apikey}"
            md5 = hashlib.md5()
            md5.update(sign_str.encode("utf-8"))
            return md5.hexdigest().upper()
    
        #支付函数
        def pay(self):
            self.appid=settings.AppId
            #商户号(封装文件中获取)
            self.mch_id=settings.pay_mchid
            #随机字符串(上面自定义函数获取)
            self.nonce_str=self.get_str()
            #商品描述(实际情况来)
            self.body="饼哥生活费"
            #订单号(自定义函数获取)
            self.out_trade_no=self.get_order()
            #支付金额
            self.total_fee=1
            #终端ip
            self.spbill_create_ip=self.ip
            #异步回调地址,根据实际情况来
            self.notify_url="http://www.baidu.com"
            #交易类型
            self.trade_type="JSAPI"
            #签名(自定义函数)
            self.sign = self.get_sign()
            #数据格式替换
            data=f'''
            <xml>
                   <appid>{self.appid}</appid>
                   <body>{ self.body}</body>
                   <mch_id>{self.mch_id}</mch_id>
                   <nonce_str>{self.nonce_str}</nonce_str>
                   <notify_url>{self.notify_url}</notify_url>
                   <openid>{self.openid}</openid>
                   <out_trade_no>{self.out_trade_no}</out_trade_no>
                   <spbill_create_ip>{self.spbill_create_ip}</spbill_create_ip>
                   <total_fee>{self.total_fee}</total_fee>
                   <trade_type>{self.trade_type}</trade_type>
                   <sign>{self.sign}</sign>
            </xml>
            '''
    
            url="https://api.mch.weixin.qq.com/pay/unifiedorder"
            #向微信官方服务接口发送数据,response为xml格式数据
            response=requests.post(url,data.encode("utf-8"),headers={"content-type":"application/xml"})
            #调用自定义函数将xml格式数据转成字典
            res_data=self.xml_to_dict(response.content)
            #二次调用自定义签名
            data=self.two_sign(res_data["prepay_id"])
            return  data
    
        #二次签名函数
        def two_sign(self,prepay_id):
            timeStamp=str(int(time.time()))
            nonceStr=self.get_str()
            data_dict={
                "appId":settings.AppId,
                "timeStamp":timeStamp, #时间戳
                "nonceStr":nonceStr, #随机字符串
                "package":f"prepay_id={prepay_id}", #数据包
                "signType":"MD5" #签名类型
            }
            sign_str = "&".join([f"{k}={data_dict[k]}" for k in sorted(data_dict)])
            sign_str = f"{sign_str}&key={settings.pay_apikey}"
            md5 = hashlib.md5()
            md5.update(sign_str.encode("utf-8"))
            sign=md5.hexdigest().upper()
            data_dict["paySign"]=sign
            data_dict.pop("appId")
    
            return  data_dict
    
    
    
    def get_access_token():
        accesston=requests.get()
  • 相关阅读:
    类加载器
    类加载器
    类加载器
    类加载器
    Java11新特性
    Java11新特性
    Spring Cloud Alibaba学习笔记(24)
    Java11新特性
    PyCharm Professional 2016.1 破解 激活
    pycharm最新激活码 2018 2.28 到期
  • 原文地址:https://www.cnblogs.com/tfzz/p/12590468.html
Copyright © 2011-2022 走看看