WeChat 公式アカウントのスキャン コードを使用して Web サイトへのログインを実現する - Django+Vue バージョン - 超詳細なナニー レベルのチュートリアル


Web ページで WeChat スキャン コード ログインを実現するには 3 つの方法があります。

  • PlanA: Wechat オープン プラットフォーム - 認定が必要 - 300 元
  • PlanB: WeChat パブリック アカウント - サービス アカウントが必要で、認証済み - 300 元
  • PlanC: Wechat ミニ プログラム - オンラインで登録されたミニ プログラム - 0 元

このチュートリアルは、Django+vue の WeChat 公式アカウント スキャン コード ログインの例です。WeChat スキャン コード ログインから、公式アカウントの登録から最終的なプロセス全体の実現まで、github のリンクが添付されます。基本的な考えをもとに、自分の状況に応じて変更していくというプロセスを一歩ずつ進めていけば、必ず実現します。詳細が記載されます。

最終的な効果を実現するためのデモ

ここに画像の説明を挿入
ここに画像の説明を挿入



この記事では、ロジックとプロセスを実装します。WeChat が提供する一時的な QR コードを使用してフロントエンドに戻り、フロントエンドでのロング ポーリングを有効にしてバックエンドのログイン ステータスを要求します。ユーザーはコードをスキャンして WeChat 公式アカウントにジャンプします。新規ユーザーの場合は注意が必要です。フォロー後、WeChat は公式アカウントに戻ります。古いユーザーの場合、WeChat は公式アカウントに戻り新用户登录成功ますアカウント老用户登录成功公式アカウントに戻ったら、キーの認証情報を対応するユーザーに保存します。フロントエンドのロングポーリングクエリは、データベースにこのデータがあることを検出し、ユーザー情報を返し、ログインは成功します。長いポーリングが終了すると、フロントエンドはジャンプしてログインが成功したことを示します。


受験番号を申請する


  • 公開番号を登録する

まずはWeChat公式アカウントの登録ですが、気軽に登録するだけですが、オンラインで利用したい場合は忘れずにサービスアカウントの申請を行ってください。サービスアカウントとサブスクリプションアカウントの違いについては割愛します。関連するニーズがある場合は、WeChat 公式ビューに移動できます。

登録完了後、左側设置与开发下部をクリックする接口权限と、関連機能に必要な公式アカウントのカテゴリーが簡単に表示されます。一般的に申請するのは個人番号であり、基本的に何の機能も持たず、記事の投稿のみが可能です。
ここに画像の説明を挿入

公開アカウント登録リンク
https://mp.weixin.qq.com/cgi-bin/registermidpage?action=index&lang=zh_CN



  • テスト番号を入力してください

場所:左側のナビゲーション バー开发者工具の下公众平台测试账号

ここに画像の説明を挿入

入力すると、 appIDappsecretが与えられます。これらは重要なパラメータであり、後でテストするために使用されます。このインターフェイス構成情報は、WeChat バックエンドと対話するための鍵となります。

ここに画像の説明を挿入



  • インターフェース構成情報の実装

ここに画像の説明を挿入

WeChat と対話するには、このインターフェイスを通じて情報を構成する必要があります。完了後、[テストの送信] をクリックすると、テストに合格した後、後続の操作に進むことができます

URL必须 http:// 或者 https:// 开头,分别支持80端口和443端口
Token为英文或数字,长度为3-32字符

PS:意思就是你要有一个在线上的服务器,开启了80端口和443端口
然后你填写一个接口的URL,确保线上服务器的这个接口能用,能被微信访问到
然后在你填写的后端API上,做出对微信的响应

インターフェイス構成情報の元のリンク: https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Access_Overview.html


Django 実装のアイデア:

from django.http import HttpResponse
from rest_framework.response import Response
from rest_framework.views import APIView
import hashlib

class WeChatSignature(APIView):
    def get(self, request):
        signature = request.query_params.get("signature")
        timestamp = request.query_params.get("timestamp")
        nonce = request.query_params.get("nonce")
        yue_token = 'yueyue'
        sort_str = ''.join(sorted([yue_token, timestamp, nonce]))
        hash_str = hashlib.sha1(sort_str.encode()).hexdigest()
        if hash_str == signature:
            return HttpResponse(request.query_params.get("echostr"), content_type="text/html; charset=utf-8")
        else:
            return Response("Invalid signature", status=403)

URLとトークンを入力したら、「送信」をクリックします。WeChat公式アカウントに入力したトークンは、サンプルコードのyue_tokenと同じである必要があります。他のものをコピーするだけです。トークンを使用して WeChat にアクセスし、正常に検証できるかどうか





パラメータ付きの QR コードを取得する


以上がドッキングの準備作業であり、次にアプリケーションコードを説明します。まず、フロントエンドはページを開いてログイン用の QR コードを要求する必要があり、バックエンドは WeChat にアクセスして、要求に従って QR コード リンクを取得します。ドキュメントを読むことをお勧めします。いくつかのパラメータと詳細に注意を払う必要があります。Django を使用している場合は、コードを直接見ることで一般的な意味を理解できます。

パラメーターを使用した QR コードの生成 元のリンク: https://developers.weixin.qq.com/doc/offiaccount/Account_Management/Generating_a_Parametric_QR_Code.html

実装手順:

  • 公式アカウントのグローバルインターフェース呼び出し認証情報を取得(有効期間2時間) AccessToken
  • QRコードチケットを取得する
  • QRコードのURLを取得するためのチケット接続URL
  • シーン (最後のポーリングで使用された) と URL をフロントエンドに返します。

ジャンゴコード:

import requests
import uuid
import json

# Demo先定义在View中,这两个参数在测试号管理页看得到
appID = "wx8axxxxxx236efe2a"
appSecret = "131b8d9dxxxxxxxx11d3b751ce6b2"

class WeChatLogin(APIView):
    """
    微信登录
    """

    def get(self, request):
        qr_data = self.createShortTicket(str(uuid.uuid4()))
        qr_code_url = "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket={}".format(qr_data[0])
        return Response({
    
    'url': qr_code_url, 'scene': qr_data[1]})

    def createShortTicket(self, scene_str):
        """
        生成短效二维码
        :param scene_str:
        :return:
        """
        print("scene_str-------{}".format(scene_str))
        url = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token={}".format(self.getAccessToken())
        data = {
    
    
            "expire_seconds": 180,              # 二维码有效时间, 以秒为单位
            "action_name": "QR_STR_SCENE",      # 二维码类型, QR_STR_SCENE为临时的字符串参数值
            "action_info": {
    
                        # 二维码详细信息
                "scene": {
    
    
                    "scene_str": scene_str      # 场景值ID(字符串形式的ID, 字符串类型, 长度限制为1到64
                }
            }
        }
        return [json.loads(requests.post(url, json=data).content.decode("utf-8")).get("ticket"), scene_str]

    def getAccessToken(self):
        """
        获取公众号全局接口调用凭证(有效期2h)
        建议公众号开发者使用中控服务器统一获取和刷新access_token
        """
        url = 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={}&secret={}' \
            .format(appID, appSecret)
        return requests.get(url).json().get('access_token')

Vue コード:

getQrUrl() {
    
    
      axios.get('https://api.xxxxx.pro/api/weChatLogin').then((res) => {
    
    
        console.log(res.data);
        this.qr_url = res.data.url
        this.scene = res.data.scene
        this.loading = false
      })
    }
// getQrUrl我放mounted里面的,打开页面就会执行这个方法

このときフロントエンドで取得したURLがQRコードのURLとなり、直接クリックしてQRコードを表示したり、自分で画像に埋め込むことも可能です。



ユーザー スキャン コード コールバックを処理する

この QR コードには、チケットとシーン、ログインが成功したことを確認するための唯一の認証情報として使用するパラメータが含まれます。ここではシーンを使用します。チケットを使用するとはるかに便利になりますが、コードを変更するのは面倒です。以前は、チケットが同時実行の決定と競合するかどうかは不明でした。ここにはテスト用に大量の印刷物が書き込まれていますが、必要に応じて削除してください。
ここで、定義した WeChatSignature インターフェイスの get メソッドは WeChat の検証に使用され、投稿は WeChat が呼び出すものであることを明確にする必要があります。
ユーザーがログインするために指定した QR コードをスキャンした後。WeChat は XML をサーバーにコールバックします。ET を使って解析し、必要なパラメータを取得するだけです。ここには if 判定がたくさん書かれています。イベントの種類は元のドキュメントを読むと理解できます。

イベントのフォロー/フォロー解除の元文書:
https://developers.weixin.qq.com/doc/offiaccount/Message_Management/Receiving_event_pushes.html
公式アカウントの返信メッセージの元文書:
https://developers.weixin.qq.com/doc/ offiaccount /Message_Management/Passive_user_reply_message.html#0

最初に XML を印刷して確認することができます
ここに画像の説明を挿入

ジャンゴコード:


import xml.etree.ElementTree as ET
from django.utils import timezone
from app.models import TextMsg, User

class WeChatSignature(APIView):
    def get(self, request):
        signature = request.query_params.get("signature")
        timestamp = request.query_params.get("timestamp")
        nonce = request.query_params.get("nonce")
        yue_token = 'yueyue'
        sort_str = ''.join(sorted([yue_token, timestamp, nonce]))
        hash_str = hashlib.sha1(sort_str.encode()).hexdigest()
        if hash_str == signature:
            return HttpResponse(request.query_params.get("echostr"), content_type="text/html; charset=utf-8")
        else:
            return Response("Invalid signature", status=403)

    def post(self, request):
        """
        to_user_name: 公众号的微信号
        from_user_name: 发送方OpenId
        create_time:消息创建时间(时间戳)
        msg_type: 消息类型
        :return:
        """
        wx_data = request.body
        xml_data = ET.fromstring(wx_data)
        to_user_name = xml_data.find('ToUserName').text
        from_user_name = xml_data.find('FromUserName').text
        create_time = xml_data.find('CreateTime').text
        msg_type = xml_data.find('MsgType').text
        event_key = xml_data.find('EventKey').text
        print('---------------------------')
        print("EventKey---------{}".format(event_key))
        print('---------------------------')
        if msg_type == 'event':
            event = xml_data.find('Event').text
            print(event)
            # 如果未关注
            if event == 'subscribe':
                tmp_scene_str = event_key.split('_')[1]
                scene_str = User.objects.filter(tmp_scene_str=tmp_scene_str)
                # 如果查询到此凭证已经存在,就证明此二维码已经被人扫过且登录了。直接走else
                if not scene_str.exists():
                    ticket = xml_data.find('Ticket').text
                    print("ticket-----------{}".format(ticket))
                    datetime_obj = timezone.datetime.fromtimestamp(int(create_time))
                    create_time = datetime_obj.strftime('%Y-%m-%d %H:%M:%S')
                    new_user = User.objects.get_or_create(openId=from_user_name)[0]
                    new_user.tmp_scene_str = tmp_scene_str
                    new_user.lastLoginTime = create_time
                    new_user.save()
                    xml_text = TextMsg(to_user_name, from_user_name, '新用户--登录成功').structReply()
                else:
                    xml_text = TextMsg(to_user_name, from_user_name, '二维码已失效').structReply()
                return HttpResponse(xml_text)
            # 如果关注了
            elif event == 'SCAN':
                scene_str = User.objects.filter(tmp_scene_str=event_key)
                # 同上,码被扫过,登录了就不走这里了
                if not scene_str.exists():
                    ticket = xml_data.find('Ticket').text
                    print("ticket-----------{}".format(ticket))
                    datetime_obj = timezone.datetime.fromtimestamp(int(create_time))
                    create_time = datetime_obj.strftime('%Y-%m-%d %H:%M:%S')
                    User.objects.filter(openId=from_user_name).update(tmp_scene_str=event_key, lastLoginTime=create_time)
                    xml_text = TextMsg(to_user_name, from_user_name, '老用户--登录成功').structReply()
                else:
                    xml_text = TextMsg(to_user_name, from_user_name, '二维码已失效').structReply()
                return HttpResponse(xml_text)
         # 如果不是你已知的微信回调,就返回一个故障。。
        xml_text = TextMsg(to_user_name, from_user_name, '服务器故障,请联系管理员或重试').structReply()
        return HttpResponse(xml_text)

WeChat のコールバックが追跡されたイベントかどうかを判断する上記のコードの機能を説明します。User テーブルに移動して、このevent_key があるかどうかを確認します。WeChat からコールバックされるevent_key は、前に定義した scene_str です。ただし、注意を払うことと、フォローされていない場合に返すことには違いがあることに注意してください。一方にはプレフィックスがあり、他方にはプレフィックスがありません。ドキュメントが書かれているので、行って見てください。それは私のコードでも処理されます。from_user_name を通じてどのユーザーがログインしているかを確認し、scene_str を一時的な資格情報として保存します。WeChat に返される XML は処理および解析する必要があります。ここでは、models.py で定義します。これは TextMsg メソッドですが、ちなみに User も貼り付けられます。フォーマットされて文字列に返された HttpResponse が WeChat 公式アカウントに返されます。ひょうたんの絵に従って、自分で変更してください。後続のフロントエンド ポーリングでは、データベースに scene_str が存在するかどうかを確認するだけで済みます。存在する場合は、この scene_str に対応するユーザーデータをフロントエンドに返します。

モデル.py

from django.db import models
import time

class TextMsg:
    def __init__(self, to_user, from_user, recv_msg):
        self._toUser = to_user
        self._fromUser = from_user
        self._recvMsg = recv_msg
        self._nowTime = int(time.time())

    def structReply(self):
        text = """
                <xml>
                <ToUserName><![CDATA[{}]]></ToUserName>
                <FromUserName><![CDATA[{}]]></FromUserName>
                <CreateTime>{}</CreateTime>
                <MsgType><![CDATA[text]]></MsgType>
                <Content><![CDATA[{}]]></Content>
                </xml>
                """.format(self._fromUser, self._toUser, self._nowTime, self._recvMsg)  # 前面两个参数的顺序需要特别注意
        return text


class User(models.Model):
    openId = models.CharField(null=True, blank=True, max_length=200, verbose_name='用户唯一凭证')
    tmp_scene_str = models.CharField(null=True, blank=True, max_length=100, verbose_name='登录临时凭证')
    lastLoginTime = models.CharField(null=True, blank=True, max_length=50, verbose_name='最后登录时间')


フロントエンドのロングポーリング

理解しやすいように、以前の getQrUlr も貼り付けられています。これは、ユーザーが Web ページを開くと getQrUrl の実行が開始されることを意味します。次に、ロングポーリングのloginPollメソッドをオンにします。これはテスト用にここに書きました。開発時に自分で変更できます。

Vueコード

methods: {
    
    
    getQrUrl() {
    
    
      axios.get('https://api.xxxx.pro/api/weChatLogin').then((res) => {
    
    
        console.log(res.data);
        this.qr_url = res.data.url
        this.scene = res.data.scene
        this.loading = false
      })
      this.tem_poll = setInterval(this.loginPoll, 1000)
    },

    loginPoll() {
    
    
    // 这里就是请求后端的时候顺便带上这个scene
      axios.get('https://api.xxxxx.pro/api/verifyLogin?scene=' + this.scene).then((res) => {
    
    
        console.log(res.data);
        if (res.data == 'success') {
    
    
        // 清除定时器
          clearInterval(this.tem_poll)
          this.$notify({
    
    
            title: '登录成功',
            type: 'success',
            duration: 0
          });
          return;
        }
      })
    }
  }

ジャンゴコード

class VerifyLogin(APIView):
    def get(self, request):
    	# 拿到前端给的scene
        scene_str = request.query_params.get('scene')
        # 查询数据库有没有此scene
        tmp_scene_str = User.objects.filter(tmp_scene_str=scene_str)
        print('scene_str-----------{}------------'.format(scene_str))
        print('tmp_scene_str-----------{}------------'.format(tmp_scene_str))
        # 如果有的话就证明这个用户扫码已经关注了,要么是新用户关注进来要么是老用户扫码进来
        if tmp_scene_str:
            print('-------------登录成功!-------------')
            return Response('success')
        # 如果没登陆就一直返回空
        return Response({
    
    })

フロントエンドのロングポーリングが成功したらログイン成功、あとはどのページに飛んで何をするか業務に合わせてやればいい 全体のロジックは複雑ではないが、WeChatドキュメントが
曖昧。今後メッセージをプッシュしたい場合は、上記の投稿方法が便利です

テンプレート メッセージを送信するには、このチュートリアルを参照してください。

WeChat パブリック アカウント テンプレート メッセージ プッシュ テスト サーバーなしの Python バージョン - 乳母レベルのチュートリアル
https://blog.csdn.net/qq_44718932/article/details/132223216



上記のチュートリアルの手順はすべて終了しました。フロントエンドは Ele.me UI を使用しています。すべてのコードが必要な場合は、github で確認できます。役に立つと思ったら、ぜひSanlianにお越しください。理解できないコメントについては、メールのリマインダーを開いて、見つけ次第返信しました

Github アドレス: https://github.com/BioYue/WeChatLogin

おすすめ

転載: blog.csdn.net/qq_44718932/article/details/132316160