• 【小程序码】登录的技术实现案例


    前言

    我准备给彩虹屁老婆插件开发一个皮肤/模型下载网站,里面需要具备用户系统。但我又得去完整开发一套注册,用户激活机制

    不过当时我的第一反应是可以利用微信公众号的扫码登录,但公众号的扫码登录接口必须得是服务号才可以使用。服务号的注册又必须使用营业执照走企业认证,总之比较麻烦。恰好当时我的小程序猿创聚合助手已经发布了,所以我就在思考,能否直接利用小程序码的接口来自己设计一套扫码登录流程呢?

    如何实现

    经过一番思考和调研,我确定以下方式是可行的

    利用生成小程序码的接口wxacode.getUnlimited,我们可以生成无限个数的小程序码,虽然该接口携带参数有些限制,但不影响整个逻辑的实现。

    扫小程序码登录逻辑如下:

    未命名.001.jpeg

    核心技术点

    生成时间戳签名

    Web端生成的时间戳签名必须得是唯一的,如果出现不唯一的签名,用户登录就会乱套了。而生成小程序码所使用的getUnlimited接口仅允许携带一个scene参数,长度要求为32个字符以内。

    保证唯一性有很多GUID/UUID的方案,但在本例里,小程序码携带参数的字符数量是有限制的,所以常见方案都不太适合。我最后找到的是nanoid这个方案,非常符合我的需求。

    /*
    一个小巧、安全、URL友好、唯一的 JavaScript 字符串ID生成器。
    
    “一个惊人的无意义的完美主义水平, 这简直让人无法不敬佩。”
    
    **小巧.**  130 bytes (已压缩和 gzipped)。 没有依赖。 [Size Limit](https://github.com/ai/size-limit) 控制大小。
    **快速.**  它比 UUID 快 60%。
    **安全.**  它使用加密的强随机 API。可在集群中使用。
    **紧凑.**  它使用比 UUID(`A-Za-z0-9_-`)更大的字母表。 因此,ID 大小从36个符号减少到21个符号。
    **易用.**  Nano ID 已被移植到 [19种编程语言](https://github.com/ai/nanoid/blob/main/README.zh-CN.md#%E5%85%B6%E4%BB%96%E7%BC%96%E7%A8%8B%E8%AF%AD%E8%A8%80)。
    */
    
    import { nanoid } from 'nanoid'
    model.id = nanoid() //=> "V1StGXR8_Z5jdHi6B-myT"
    复制代码

    生成小程序码

    这里需要注意的是,我们在web端里通过调用生成小程码的接口,将最终的小程序码显示在网页里。scene是一个不可变的参数名,参数内容里放的是时间戳签名。

    
    
    async function getWXACodeUnlimited(scene,page){
        const access_token = await getAccessToken();
        const res = await uniCloud.httpclient.request("https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token="+access_token,{
            method:"POST",
            headers:{
                "Content-Type":"application/json"
            },
            data:{
                scene:scene,
                page:page
            }
        });
        
        return res.data;
    }
    
    
    • 扫描小程序码获取签名

    使用微信扫描小程序码后,会进入到小程序并打开指定的page(小程序内页面),在该页面的onLoad事件中可以拿到scene参数。

    onLoad(options) {
        var scene = options.scene;
        var loginToken;
    
        if(scene){
          loginToken = scene;
        }
    
        wx.login({
            success: (res) => {
                cloudApi.callFunction({
                    name:"users",
                    data:{
                        action:"login",
                        code:res.code,
                        logintoken:loginToken
                    },
                    success: (res) => {
                        
                    }
                })
            }
        })
    }
     

    上述代码中实现的是,通过login接口获取到code,用于请求code2session接口换取小程序用户的openid,这一步完成,我们等于就在小程序里完成了用户登录。

    然后怎么把信息同步给Web端呢?就是这个LoginToken,我这里把它写到与openid相同的用户表数据条目中,然后web端会通过loginToken轮询这个用户数据表,发现匹配数据后返回给Web端,完成Web端的登录

    if(loginToken){
        await db.collection("users").where({
            openid:dbCmd.eq(openid)
        }).update({
            lastlogin:Date.now(),
            loginToken:dbCmd.set({
                value:loginToken,
                expiretime:Date.now()+60*3*1000000
            })
        })
    }
     

    现在我们已经完成了扫小程序码登录机制,用户登录网站时,也可以增加小程序的用户和日活跃用户数。

    轮询优化

    1. 点击登录时生成并显示小程序码,此时开启轮询,每5秒查询一次数据库。
    2. 查询到匹配的用户信息,结束轮询,完成登录。
    3. 在三分钟内如果查询不到匹配的用户信息,结束轮询。
  • 相关阅读:
    挂载银行前置机Ukey到windows server2012虚拟机的操作记录
    LVS负载均衡下session共享的实现方式-持久化连接
    Centos6.9下RabbitMQ集群部署记录
    Linux下绑定网卡的操作记录
    Redis Cluster集群知识学习总结
    Redis Cluster日常操作命令梳理
    android Unable to inflate view tag without class attribute
    java / android int类型如何判空?
    Android 倒计时按钮,倒计时发送短信验证码…
    Android 自定义View
  • 原文地址:https://www.cnblogs.com/huangjiangyong/p/15407322.html
Copyright © 2020-2023  润新知