django实现微信公众号扫码登录

首先是去获取access_token,access_token接口有次数限制,所以保存到缓存,失效时再去调用接口

 

import base64
import json
import time
import traceback

import requests
from django.core.cache import cache
from rest_framework.response import Response
from rest_framework.views import APIView

app_id = 'xxxxxxx'  # appid
app_secret = 'xxxxxx'   # app密钥
msg_key = 'xxxxxx'  # 消息模板id
app_token = "xxxxxxx"   # apptoken


def get_wx_access_token():
    """
    获取access_token,保存到缓存
    :return:
    """
    url = 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={0}&secret={1}'.format(app_id, app_secret)
    resp = requests.get(url)
    # print(resp.json())
    access_token = resp.json()['access_token']
    cache.set('wx_access_token', access_token, 60*60*2)
    # print(access_token)
    return access_token


def get_ticket(access_token, scene_str=''):
    """
    获取ticket
    :param access_token:
    :param scene_str:
    :return:
    """

    url = 'https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token={0}'.format(access_token)
    # print(scene_id)
    data = {
        "expire_seconds": 604800,
        "action_name": "QR_STR_SCENE",
        "action_info": {"scene": {'scene_str': scene_str}}  # 一定要取字符串,整形有最大值限制
    }
    resp = requests.post(url, data=json.dumps(data))
    # print(resp.json())
    ticket = resp.json()['ticket']
    return ticket


def get_code_img(ticket):
    """
    获取二维码,保存位图片
    :param ticket:
    :return:
    """
    url = 'https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=' + ticket
    resp = requests.get(url)
    # print(resp.content)
    img = base64.b64encode(resp.content).decode('ascii')
    fileData = base64.urlsafe_b64decode(img.encode('UTF-8'))
    with open('thefilename.png', 'wb') as theFile:
        theFile.write(fileData)
    # print(img)
    return img


from rest_framework.throttling import AnonRateThrottle


# 限制调用次数
class CustomAnonRateThrottle(AnonRateThrottle):
    THROTTLE_RATES = {"anon": "5/min"}


# 获取二维码
class WxGetCode(APIView):
    throttle_classes = [CustomAnonRateThrottle]

    def get(self, request):

        # cache.delete('wx_access_token')
        # body = request.query_params.dict()
        # scene_id = get_json_values('scene_id', body, 1)
        scene_str = str(int(time.time()*100000))
        # print(scene_str)
        access_token = cache.get('wx_access_token') if cache.get('wx_access_token') else get_wx_access_token()
        ticket = get_ticket(access_token, scene_str)
        # code_img = get_code_img(ticket)

        code_url = 'https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=' + ticket

        resp = {'data': code_url, 'sceneStr': scene_str}
        return Response(resp)

 

 

 

下面get请求是公众号回调时需要验证token的接口,post请求是扫码完成以后回调的接口
微信回调的是xml形式,需要让django允许解析xml格式参数

import datetime
import hashlib
import time
import traceback

import requests
from django.core.cache import cache
from django.http import HttpResponse
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework_xml.parsers import XMLParser

from wxgetcode import get_wx_access_token, app_token, msg_key


class TextXMLParser(XMLParser):
    media_type = 'text/xml'
# 

class weixin(APIView):
    parser_classes = (TextXMLParser,)

    def get(self, request):
        # 自己写的授权
        # print(request.method)
        data = request.GET
        # print(data)
        signature = data.get("signature")
        # print(signature)
        if not signature:
            return HttpResponse("dasdfafd")
        # print("sign", signature)
        timestamp = data.get("timestamp")
        nonce = data.get("nonce")
        echostr = data.get("echostr")
        # token 为用户在微信公众平台自定义token
        token = app_token
        # 将token、timestamp、nonce三个参数进行字典序排序
        list = [token, timestamp, nonce]
        list.sort()
        # 将三个参数字符串拼接成一个字符串进行sha1加密
        info = "".join(list)
        sha1 = hashlib.sha1()
        sha1.update(info.encode())
        hashcode = sha1.hexdigest()
        # 比对相同就返回 echostr
        if hashcode == signature:
            return HttpResponse(echostr)
        else:
            return ""

    def post(self, request):

        param = request.query_params.dict()
        # print(param)
        dic = request.data
        # EventKey场景码,获取二维码时返回的sceneStr
        EventKey = dic.get('EventKey')
        if dic.get('MsgType') == 'event':

            if dic.get('Event') == 'subscribe':
                # print('新用户')
                # parse_subscribe(dic)  # 新关注用户扫码
                access_token = cache.get('wx_access_token') if cache.get(
                    'wx_access_token') else get_wx_access_token()
                open_id = param.get('openid')
                # print(access_token)
                # print(open_id)
                url = f"https://api.weixin.qq.com/cgi-bin/user/info?access_token={access_token}&openid={open_id}&lang=zh_CN"
                res = requests.get(url)
                # print(res.json())
                res = res.json()
                unionid = res.get('unionid')

                # 处理逻辑
                pass

                # 完成登录公众号推送消息
                send_wx_msg(access_token, open_id)


            elif dic.get('Event') == 'SCAN':
                # print('老用户')
                access_token = cache.get('wx_access_token') if cache.get('wx_access_token') else get_wx_access_token()
                open_id = param.get('openid')
                # print(access_token)
                # print(open_id)
                url = f"https://api.weixin.qq.com/cgi-bin/user/info?access_token={access_token}&openid={open_id}&lang=zh_CN"
                res = requests.get(url)
                # print(res.json())
                res = res.json()
                unionid = res.get('unionid')
                # parse_scan(dic)  # 已经关注用户扫码

                # 处理逻辑
                pass

                # 完成登录公众号推送消息
                send_wx_msg(access_token, open_id)

        resp = 'success'
        return HttpResponse(resp)


def send_wx_msg(ACCESS_TOKEN, openid):
    """
    消息推送,根据消息模板的定义传值即可
    :param ACCESS_TOKEN:
    :param openid:
    :return:
    """
    url = f'https://api.weixin.qq.com/cgi-bin/message/template/send?access_token={ACCESS_TOKEN}'
    data = {
        "touser": openid,
        "template_id": msg_key,
        "url": "http://weixin.qq.com/download",
        "topcolor": "#FF0000",
        "data": {
            'character_string3': {'value': 'xxxxxxx', "color": "#173177"},
            'thing2': {'value': 'xxx', "color":"#173177"},
            'keyword2': {'value': 'ssss', "color": "#173177"},
            'time4': {'value': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'), "color": "#173177"},

            'keyword5': {'value': 'ssss', "color": "#173177"},

        }
        }
    res = requests.post(url, json=data)
    # print(res.json())

 



 

posted @ 2023-08-01 14:52  Wchime  阅读(283)  评论(0编辑  收藏  举报