没有任何的套路,扫描关注微信公众号就可以随意调试ChatGPT了,你还不赶紧试试。

224 阅读4分钟

最近项目有个需求要增加一个登录方式。通过扫码关注公众号实现登录。而如今,随着微信普及程度大大增加,通过微信扫描网站的二维码进行登录,不仅减少了用户注册成本,而且能够实现用户的引流,极大提高用户体验。(做完才知道个人订阅号没有权限获取带场景的二维码)

实现思路

  • 使用公众号接口生成二维码。
  • 系统接收微信推送过来的事件(关注/扫码)。
  • 用户点击关注或者扫描二维码后台都会接收到推送通知,然后根据通知实现自己的业务就可以了。

先来看看整个流程图的时序图

来捋一下整个流程:

  1. 先是用户来访问咋们的网站
  2. 咋们的网站肯定是要给他一个二维码扫,肯是需要去请求微信开放平台
  3. 用户扫码关注后,我们就会收到微信的回调事件,我们只需要处理这个回调事件就知道这个用户登录了。然后获取该用户的基本信息完成登录。

代码实现

以下代码是采用fastapi框架实现,redis是采用aioredis

1.获取access_token.可以把获取的access_token存入缓存redis中,并设置过期时间,这样中就不用重复调用。

async def get_access_token():
    """
    获取到的凭证
    return {"access_token":"ACCESS_TOKEN","expires_in":7200}
    """
    #1、获取access_token
    url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={}&secret={}".format(settings.APPID,settings.APPSECRET)
    #2、存入redis
    if await redis_tools.is_existsKey("access_token"):
        return await redis_tools.get("access_token")
    else:
        res = requests.get(url).json()
        await redis_tools._set("access_token",res.get("access_token"))
        return res.get("access_token")

redis_tools是自己封装的redis工具类。上述的代码实现获取access_token。先去判断redis中有没有存在这个access_token这键,没有就去微信公众平台获取。

2.获取生成二维码的ticket,这个也是同样的做法。代码如下:

async def generate_qrcode(token:str):
    """
    生成二维码
    return 
    {
        "ticket":"gQH47joAAAAAAAAAASxodHRwOi8vd2VpeGluLnFxLmNvbS9xL2taZ2Z3TVRtNzJXV1Brb3ZhYmJJAAIEZ23sUwMEmm3sUw==",
        "expire_seconds":60,
        "url":"http://weixin.qq.com/q/kZgfwMTm72WWPkovabbI"
    }
    """
    url = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token={}".format(token)
    data = {
        "expire_seconds": 604800,
        "action_name": "QR_SCENE",
        "action_info": {
            "scene": {
                "scene_id":123
            }
        }
    }
    #判断redis是否存在ticket
    if await redis_tools.is_existsKey("access_token"):
        return await redis_tools.get("ticket")
    else:
        res = requests.post(url,data).json()
        await redis_tools._set("ticket",res.get("ticket"),res.get("expire_seconds"))
        return res.get("ticket")

其中scene_id是根据自己的业务来填具体的值。详细的用法请参考手册

这样前端页面就可以获取到这个ticket,然后携带这个值,去请求https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket={}这个地址就可以获取到一个带参数的二维码了。

扫描带参数二维码事件

用户扫描带场景值二维码时,可能推送以下两种事件:

  • 如果用户还未关注公众号,则用户可以关注公众号,关注后微信会将带场景值关注事件推送给开发者。
  • 如果用户已经关注公众号,则微信会将带场景值扫描事件推送给开发者。

1、用户未关注时,进行关注后的事件推送

推送XML数据包示例:

<xml>
  <ToUserName><![CDATA[toUser]]></ToUserName>
  <FromUserName><![CDATA[FromUser]]></FromUserName>
  <CreateTime>123456789</CreateTime>
  <MsgType><![CDATA[event]]></MsgType>
  <Event><![CDATA[subscribe]]></Event>
  <EventKey><![CDATA[qrscene_123123]]></EventKey>
  <Ticket><![CDATA[TICKET]]></Ticket>
</xml>
参数描述
ToUserName开发者微信号
FromUserName发送方帐号(一个OpenID)
CreateTime消息创建时间 (整型)
MsgType消息类型,event
Event事件类型,subscribe
EventKey事件KEY值,qrscene_为前缀,后面为二维码的参数值
Ticket二维码的ticket,可用来换取二维码图片

2、用户已关注时的事件推送

推送XML数据包示例:

<xml>
  <ToUserName><![CDATA[toUser]]></ToUserName>
  <FromUserName><![CDATA[FromUser]]></FromUserName>
  <CreateTime>123456789</CreateTime>
  <MsgType><![CDATA[event]]></MsgType>
  <Event><![CDATA[SCAN]]></Event>
  <EventKey><![CDATA[SCENE_VALUE]]></EventKey>
  <Ticket><![CDATA[TICKET]]></Ticket>
</xml> 

参数描述
ToUserName开发者微信号
FromUserName发送方帐号(一个OpenID)
CreateTime消息创建时间 (整型)
MsgType消息类型,event
Event事件类型,SCAN
EventKey事件KEY值,是一个32位无符号整数,即创建二维码时的二维码scene_id
Ticket二维码的ticket,可用来换取二维码图片

3、前端通过轮询方式检查用户是否关注或者扫描了

微信用户通过扫描上述生成带场景值的二维码,实现扫描关注登录。关键代码如下:

  $.get("/wxmp/weChatQrCode", function (res) {
                counter = 0
                $("#qrcode").attr("src", res.data.qrcode_url);
                flag = res.data.scene_value;

                // 轮询登录状态
                timer = setInterval(() => {
                    if (counter >= 30) {
                        clearInterval(timer);
                        return
                    }
                    // 请求参数是二维码中的场景值
                    $.get("/wxmp/?wechat_flag=" + flag, function (res) {
                        counter += 1
                        if (res.code == 200) {
                            sessionStorage.setItem("token", res.data.token)
                            window.location.href = '/chatgpt';
                        }
                    })
                }, 2000);
            })

效果展示

演示地址

项目已经在gitee上开源了,可以关注微信公众号回复mp_chatgpt获取。

扫码_搜索联合传播样式-标准色版.png