zoukankan      html  css  js  c++  java
  • 11_7微信小程序之登录,支付(获取ip,requests使用),授权

    一。登录接口。

      官方文档https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/login.html

      在登录接口中,有以下步骤:

      1.通过微信函数wx获取code,request到后端。

      2.获取开发者的appid和secret和code传输到开发者url

    GET https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code

            https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/login/auth.code2Session.html

      3.获得openid和session_key自关联到数据库(open随着用户信息保存到数据库,session_key返回到前端保存)

      4。在随后的业务中带上openid获取用户,返回业务数据。

     用户视图:

    from rest_framework.views import APIView
    from rest_framework.response import  Response
    from django.core.cache import cache
    from  app01 import models
    import hashlib,time
    from app01.wx import wx_Login
    class Login(APIView):
        def post(self,request):
            param=request.data
            if param.get("code"):
                data=wx_Login.login(param.get("code"))
                if data:
                    val=data['openid']+"&"+data["session_key"]
                    key=str(int(time.time()))+data['openid']
                    md5=hashlib.md5()
                    md5.update(key.encode("utf-8"))
                    key=md5.hexdigest()
                    cache.set(key,val)
                    has_user=models.Wxuser.objects.filter(openid=data['openid']).first()
                    if not has_user:
                        models.Wxuser.objects.create(openid=data['openid'])
                    return  Response({"code":200,"msg":"ok",'data':{"login_key":key}})
    
                else:
                    return Response({"code":200,"msg":"code错误"})
            else:
                return Response({"code": 200, "msg": "缺少参数"})
    view/User
    import requests
    from app01.wx import settings
    
    def login(code):
        code_url = settings.code2Session.format(settings.AppId, settings.AppSecret, code)
        response = requests.get(code_url)
        json_response = response.json()
        if json_response.get('session_key'):
            return json_response
        else:
            return False
    wx/wx_login
    AppId=""
    
    AppSecret=""
    
    code2Session="https://api.weixin.qq.com/sns/jscode2session?appid={}&secret={}&js_code={}&grant_type=authorization_code"
    pay_mchid =''
    pay_apikey = ''
    wx/setting

    二。授权流程

       在这个授权流程中,session_key是会过期的,所以要通过checksession来判断session是否过期,

      通过getsession和getuserinfo来获取用户当前设置,和用户的信息。

      通过登录的session_key,前端传输的encryptedData,iv,login_key来解密出个人信息

      pip3 install pycryptodome

    import base64
    import json
    from Crypto.Cipher import AES
    from . 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,sessionKey):
            return cls(settings.AppId, sessionKey).decrypt(encryptedData, iv)
    wx/WXBizDataCrypt.py
    class getInfo(APIView):
        def post(self,request,*args,**kwargs):
            param = request.data
            print(request.data)
            if param['encryptedData'] and param['iv'] and param['login_key']:
                print(cache.get(param['login_key']))
                openid,session_key = cache.get(param['login_key']).split('&')
                data = WXBizDataCrypt.WXBizDataCrypt.getInfo(param['encryptedData'],param['iv'],session_key)
                save_data = {
                    "name": data['nickName'],
                    "avatar": data['avatarUrl'],
                    "language": data['language'],
                    "province": data['province'],
                    "city": data['city'],
                    "country": data['country'],
                }
                models.Wxuser.objects.filter(openid=openid).update(**save_data)
                data = models.Wxuser.objects.filter(openid=openid).first()
                data = User_ser.User_ser(instance=data,many=False).data
                return Response({"code":200,"msg":"成功","data":data})
            return Response({"code":200,"msg":"缺少参数"})
    views

    三。支付流程

      https://developers.weixin.qq.com/miniprogram/dev/api/open-api/payment/wx.requestPayment.html

      在开发文档中的数据

    pay:function(){
        wx.request({
          url: "http://127.0.0.1:8000/pay/",
          method: "POST",
          data:{"login_key":wx.getStorageSync("login_key")},
          header: { "content-type": "application/json" },
          success: function (e) {
            console.log(e)
            wx.requestPayment({
              'timeStamp': e.data.data.timeStamp,
              'nonceStr': e.data.data.nonceStr,
              'package': e.data.data.package,
              'signType': e.data.data.signType,
              'paySign': e.data.data.paySign,
              'success': function (res)
               {
                 console.log(res,"成功")
                },
              'fail': function (res) 
              {
                console.log("支付失败",res)
               },
            
    
    ```
        })
      }
    })
    ```
    
      },
    前端
     <button bind:tap="pay"> 支付</button>
    import hashlib
    import random
    import time
    from django.core.cache import cache
    
    from django.shortcuts import render
    from rest_framework.views import APIView
    from rest_framework.response import Response
    # Create your views here.
    from .wx import settings
    from .wx.wx_login import login as logins
    from . import models
    from .wx import WXBizDataCrypt
    from app01.my_ser import User_ser
    import requests
    
    class test(APIView):
        def post(self,request,*args,**kwargs):
            print(request)
            return Response(data={'msg':'ok'},status='200')
    
    class login(APIView):
        def post(self,request,*args,**kwargs):
            param = request.data
            print(param.get('code'))
            if param.get('code'):
                data = logins(param.get('code'))
                if data:
                    val = data['openid'] + '&' + data['session_key']
                    print("openid"+data['openid'],"session_key"+ data['session_key'])
                    key = data['openid'] + str(int(time.time()))
                    md5 = hashlib.md5()
                    md5.update(key.encode('utf-8'))
                    key = md5.hexdigest()
                    cache.set(key,val)
                    has_user = models.Wxuser.objects.filter(openid=data['openid']).first()
                    if not has_user:
                        models.Wxuser.objects.create(openid=data['openid'])
                    return Response({
                        "code": 200,
                        "msg": "ok",
                        "data": {"login_key": key}
                    })
                else:
                    return Response({'code':404,'msg':'code无效'})
            else:
                return Response({'code':200,'msg':'没有参数'})
    
    
    class getInfo(APIView):
        def post(self,request,*args,**kwargs):
            param = request.data
            print(request.data)
            if param['encryptedData'] and param['iv'] and param['login_key']:
                print(cache.get(param['login_key']))
                openid,session_key = cache.get(param['login_key']).split('&')
                data = WXBizDataCrypt.WXBizDataCrypt.getInfo(param['encryptedData'],param['iv'],session_key)
                save_data = {
                    "name": data['nickName'],
                    "avatar": data['avatarUrl'],
                    "language": data['language'],
                    "province": data['province'],
                    "city": data['city'],
                    "country": data['country'],
                }
                models.Wxuser.objects.filter(openid=openid).update(**save_data)
                data = models.Wxuser.objects.filter(openid=openid).first()
                data = User_ser.User_ser(instance=data,many=False).data
                return Response({"code":200,"msg":"成功","data":data})
            return Response({"code":200,"msg":"缺少参数"})
    
    
    class pay(APIView):
        def post(self,request,*args,**kwargs):
            param = request.data
            if param.get("login_key"):
                openid, session_key = cache.get(param.get("login_key")).split("&")
                self.openid = openid
                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']
                data = self.pay()
                return Response({"code":200,"msg":"ok","data":data})
            else:
                return Response({"code": 400, "msg": "缺少参数"})
    
        def get_str(self):
            str_all = "1234567890abcdefghijklmnopqrstuvwxyz"
            nonce_str = "".join(random.sample(str_all,20))
            return nonce_str
    
        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 get_order(self):
            order_id = str(time.strftime("%Y%m%d%H%M%S"))
            return order_id
    
        def pay(self):
            self.appid = settings.AppId
            self.mch_id = settings.pay_mchid
            self.nonce_str = self.get_str()
            self.body = "lzx"
            self.out_trade_no = self.get_order()
            self.total_fee = 1
            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 = requests.post(url,data.encode("utf-8"),headers={"content-type":"application/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
    view

      需要二次生成签名,并以xml的方式提交url。还需要payid。

      在django中,可以通过request中的HTTP_X_FORWARDED_FOR,进行获取,用以共给支付接口。

                if request.META.get("HTTP_X_FORWARDED_FOR"):
                    host_ip = request.META["HTTP_X_FROWARDED_FOR"]

      

    requests的使用:

    get:

    import requests
    response = requests.get("http://www.baidu.com/")
    
    # 也可以这么写
    # response = requests.request("get", "http://www.baidu.com/")

    post:

    import requests
    
    kw = {'wd':'苍井空'}
    
    headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"}
    
    # params 接收一个字典或者字符串的查询参数,字典类型自动转换为url编码,不需要urlencode()
    response = requests.get("http://www.baidu.com/s?", params = kw, headers = headers)
    
    # 查看响应内容,response.text 返回的是Unicode格式的数据
    print response.text
    
    # 查看响应内容,response.content返回的字节流数据
    print respones.content
    
    # 查看完整url地址
    print response.url
    
    # 查看响应头部字符编码
    print response.encoding
    
    # 查看响应码
    print response.status_code

      其他https://www.cnblogs.com/lowmanisbusy/p/9065359.html

  • 相关阅读:
    Entity Framework 6.0 Tutorials(10):Index Attribute
    Entity Framework 6.0 Tutorials(9):Stored Procedure Mapping
    Entity Framework 6.0 Tutorials(8):Custom Code-First Conventions
    Entity Framework 6.0 Tutorials(7):DbSet.AddRange & DbSet.RemoveRange
    Entity Framework 6.0 Tutorials(6):Transaction support
    Entity Framework 6.0 Tutorials(5):Command Interception
    Entity Framework 6.0 Tutorials(4):Database Command Logging
    Entity Framework 6.0 Tutorials(3):Code-based Configuration
    Entity Framework 6.0 Tutorials(2):Async query and Save
    JAVA-初步认识-第十章-内部类-概述
  • 原文地址:https://www.cnblogs.com/LZXlzmmddtm/p/11817133.html
Copyright © 2011-2022 走看看