最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 假期让你的博客集成微信小程序扫码登录

    正文概述 掘金(优秀笔记)   2021-05-01   489

    常见的微信扫码登录逻辑有两种

    1、微信开放平台

    2、微信服务号

    这两种都需要企业资料认证,对个人开发者是没有权限的,无意间看到腾讯文档扫码登录的时候打开的是小程序,开始还以为只有腾讯有权限(滑稽的笑了? ),然后就一顿搜索,发现这个逻辑其实就是我们日常开发小程序中的小程序码功能,外加一个websocket功能就可以搞定

    文章首发于我的博客,欢迎大家前来围观?️ ?️ ?️

    实现原理

    • 博客点击微信登录弹窗,建立websocket连接,连接建立成功之后,发送消息从服务端获取带有时间戳的随机id,接受到id之后携带id请求小程序码(id用于网页端和小程序的通信绑定),
    • 用户通过微信扫码点击登录之后,把用户信息、code、和id提交到服务端,
    • 服务端根据code获取openid,然后根据openid判断是创建还是更新用户信息,然后生成token通过websocket广播给唯一id的前端网页
    • 前端接受到token,存储token,页面重新加载获取用户信息,断开websocket连接

    前端代码实现

    //初始化weosocket
            initWebSocket() {
                if (this.websock) {
                    this.websock.close();
                }
                // websocket 消息处理
                const messageHandler = {
                    // 获得 codeId 接下来我们要生成二维码
                    CODE_ID: async (res) => {
                        let $res = await wxcodeUrl({ scene: res.data.uuid });
                        this.wxCodeSrc = "http://localhost:3000/" + $res.data.url;
                        this.codeLoading = false;
                        this.isFailure = false;
                        this.desccontent = "请使用微信扫一扫";
                    },
                    // 二维码被扫描,等待客户端确认
                    SCANNED: () => {
                        this.isLoadingScan = true;
                        this.desccontent = "请在微信中点击确认登录";
                    },
                    // 登录成功,保存获得的 token
                    SUCCESS: (res) => {
                        this.$store.commit("user/SET_TOKEN", res.data.token);
                        setToken(res.data.token);
                        location.reload();
                        this.$notify({
                            title: "成功",
                            message: "登录成功~",
                            type: "success",
                        });
                        this.codeLoading = false;
                        this.websock.close();
                    },
                };
                //初始化weosocket
                this.websock = new WebSocket("ws://localhost:3000/webSocket");
                this.websock.onmessage = (e) => {
                    const res = JSON.parse(e.data);
                    const handlerFn = messageHandler[res.data.type];
                    // 匹配到相应的函数,执行之
                    if (typeof handlerFn === "function") {
                        handlerFn(res);
                    }
                };
                // 连接建立成功
                this.websock.onopen = () => {
                    // 发送消息,请求随机 id
                    this.websock.send("GET_CODE");
                };
                this.websock.onerror = this.websocketonerror;
                this.websock.onclose = this.websocketclose;
            },
            //连接建立失败重连
            websocketonerror() {
                this.initWebSocket();
            },
            //关闭连接
            websocketclose() {
                this.isFailure = true;
                this.isLoadingScan = false;
                this.desccontent = "";
            },
    

    服务端代码

    app.listen(3000);
    app.on('error', onError);
    app.on('listening', onListening);
    
    // websocket 初始化
    const wss = createWss(server);
    initWebsocket(wss);
    
    • WebSocket Server 对象
    const WebSocket = require('ws');
    
    // WebSocket Server 对象
    let wss = null;
    
    // 创建 wss 对象,我们可以把 Koa 的 Server 的对象传入,来共享端口,
    // 第一次创建时,我们会结果赋值给将上面的 wss,
    // 这样的好处是方便在接口层中获取 wss 对象,匹配正确的客户端
    const createWss = (server) => {
        if (!wss) {
            wss = new WebSocket.Server({
                server: server
            })
            return wss;
        } else {
            return wss;
        }
    }
    
    // 获取 wss 对象
    const getWss = () => {
        return wss;
    }
    
    
    module.exports = {
        createWss: createWss,
        getWss: getWss
    }
    
    • 初始化后的事件
    // 发送消息
    const sendData = (client, status, data) => {
        if (client && client.send) {
            client.send(JSON.stringify({
                status: status,
                data: data
            }));
        }
    }
    
    // 服务初始化
    const initWebsocket = (wss) => {
        wss.on("connection", (ws) => {
            console.log(`[SERVER] connection`);
            // 接收到数据
            ws.on('message', (msg) => {
                console.log(`[SERVER] Received: ${msg}`);
                // 发送数据
                const fn = loginMessageHandler[msg];
                if (fn) {
                    fn(ws);
                } else {
                    ws.send("bad command!");
                }
            });
        });
    }
    
    // 处理登录消息,根据客户端发来的消息匹配相应的业务逻辑操作函数
    const loginMessageHandler = {
        "GET_CODE": (ws) => {
            const uid = new Date().getTime();
            console.log("获取二维码----" + uid);
            ws.loginCondition = {
                uuid: uid,
                status: 0
            }
            sendData(ws, "ok", {
                uuid: uid,
                type: "CODE_ID"
            });
        }
    }
    
    module.exports = {
        initWebsocket: initWebsocket,
        sendData: sendData
    }
    

    微信扫码登录

    /**
         * 微信扫码登录
         * @param {*} ctx 
         */
        static async wxscanLogin(ctx) {
            const { scene: uuid } = ctx.request.body;
            let payload = ctx.state.user;
            try {
                const token = tools.generatorToken({ id: payload.id });
                const wss = getWss();
                if (wss && wss.clients && token) {
                    // 可以在 wss.clients 中找到相应的客户端
                    const clients = wss.clients;
                    // 找到对应的 ws 客户端
                    let targetClient = [...clients].find((client) => client.loginCondition.uuid == uuid);
                    if (targetClient) {
                        if (targetClient.loginCondition.status == 0) {
                            sendData(targetClient, "ok", {
                                uuid: uuid,
                                type: "SUCCESS",
                                token: token
                            });
                        }
                    }
                    ctx.success();
                }
            } catch (err) {
                ctx.fail();
            }
        }
    

    演示地址 : youxiubiji.com


    起源地下载网 » 假期让你的博客集成微信小程序扫码登录

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元