微信扫码跳转小程序实现web登录

news2024/12/23 9:42:00

前面博客我有写微信扫码跳转h5实现登录,但是需要申请服务号
最近项目迭代,想到小程序能做扫码登录的话,web网页端和小程序同时登录账户不是更好吗,还不用额外申请服务号

第一步
打开微信公众平台,在“开发”菜单下点击“开发管理”,然后点击“开发设置”,滚动条向下滑动有一个“扫普通链接二维码打开小程序”,点击添加

配置二维码的链接,小程序功能页面就是扫码进去小程序的页面,保存以后一定要发布。如果链接后面要带参数,线上版本是可以正常跳转到小程序功能页面的;但是开发版本想要携带参数只能和测试链接的地址一样,但可以先试试开发版本二维码地址换成和测试链接一样看能不能正常跳转,然后再调试线上的。

第二步
web端生成二维码,微信扫码并且轮询uuid检查uuid状态,获取到小程序已经登录成功的状态码web端同时登录成功。(这里二维码的地址就是写上面小程序的二维码规则)
1.下载二维码插件
cnpm i qrcodejs2 --save
2.组件中引入

<h2>扫码登录</h2>
    <div class="qrcode-container">
      <div class="qrcode" ref="qrcode"></div>
      <img src="@/assets/images/wx_login_explain.png" class="explain" />
    </div>
    <div class="dust d-f f-d a-c j-c" v-if="needUpdate">
      <h4>二维码已失效</h4>
      <a-button type="primary" @click="update"> 点击刷新 </a-button>
    </div>
    <div class="dust d-f f-d a-c j-c" v-if="hasScan">
      <h4>登录中...</h4>
    </div>
    <p>请使用 微信扫一扫 扫描二维码登录</p>
import QRCode from "qrcodejs2";
data() {
    return {
      uuid: "",
      timer: null,
      needUpdate: false,
      hasScan: false,
    };
  },
  methods: {
    //生成二维码
    bindQRCode() {
      new QRCode(this.$refs.qrcode, {
     //上面微信公众平台申请的二维码规则
        text: "https:/xxx.cn/wx/scan?uuid=" + this.uuid,
        width: 140,
        height: 140,
        colorDark: "#333333", //二维码颜色
        colorLight: "#ffffff", //二维码背景色
        correctLevel: QRCode.CorrectLevel.L, //容错率,L/M/H
      });
      //这里主要是去除悬浮二维码时显示链接内容,不需要可以不用加上这句
      this.$refs.qrcode.removeAttribute("title");
    },
    //得到uuid,拼接在链接后面,小程序需要用到uuid
    getUuid() {
      getUuid().then((res) => {
        this.uuid = res.data.uuid;
        console.log(this.uuid);
        this.bindQRCode();
        this.timer = setInterval(() => {
          this.checkUuid();
        }, 1000);
      });
    },
    //检查uuid状态
    checkUuid() {
      checkUuid({ uuid: this.uuid }).then((res) => {
        //扫码成功,获取到token信息然后获取用户信息,web端登录成功
        if (res.data.ret === 3) {
          this.hasScan = false;
          this.needUpdate = false;
          clearInterval(this.timer);
          this.timer = null;
          let { access_token, token_type, refresh_token, scope } = res.data;
          this.$ls.set("access_token", access_token, 7 * 24 * 60 * 60 * 1000); //有效7*24小时
          this.$ls.set("token_type", token_type, 7 * 24 * 60 * 60 * 1000); //有效7*24小时
          this.$ls.set("refresh_token", refresh_token, 7 * 24 * 60 * 60 * 1000); //有效7*24小时
          this.$ls.set("scope", scope, 7 * 24 * 60 * 60 * 1000); //有效7*24小时
          getUserInfo().then((result) => {
            this.$message.success("登录成功");
            this.$ls.set("userInfo", result.data, 7 * 24 * 60 * 60 * 1000); //有效7*24小时
            this.$router.push("/enter");
          });
        }
        //失效
        else if (res.data.ret === 2) {
          clearInterval(this.timer);
          this.timer = null;
          this.needUpdate = true;
          this.hasScan = false;
        }
        //已经扫码
        else if (res.data.ret === 1) {
          this.hasScan = true;
          this.needUpdate = false;
        }
      });
    },
    //点击刷新
    update() {
      this.$refs.qrcode.innerHTML = "";
      this.needUpdate = false;
      this.getUuid();
      this.timer = setInterval(() => {
        this.checkUuid();
      }, 1000);
    },
  },
  mounted() {
    this.getUuid();
  },
  destroyed() {
    clearInterval(this.timer);
    this.timer = null;
  },

第三步
在小程序中获取到uuid然后登录流程
我的项目大概逻辑分两步,你们自己根据需求来。
第一步,进入页面得到uuid,拿wx.login的code换取unionId看是否绑定过,如果是就登录成功
第二步,如果没有绑定过就获取手机号(现在小程序获取用户手机号接口要收费),然后绑定成功后再登录成功

// pages/scan/scan.js
Page({

  /**
   * 页面的初始数据
   */
  data: {
    uuid: "",
    tenantId: "xxxx",
    unionId: "",
    showPhone: false,
    showSuccess: false,
    showNoRegister: false
  },

	//点击按钮获取手机号
  getPhoneNumber(e) {
    if (e.detail.errMsg == "getPhoneNumber:ok") {
      console.log(e.detail.code);
      let tenantId = this.data.tenantId
      let unionId = this.data.unionId
      let uuid = this.data.uuid
      
      wx.showLoading({
        title: '加载中...',
      })
      //方便看就没用封装写
      //根据code换取手机号
      wx.request({
        method: "GET",
        url: "https://xxx.cn/api-uaa/acl/wx/get-phone-number",
        data: { code: e.detail.code, tenantId },
        success: res => {
          if (res.data.errCode == 0) {
            //判断手机号有无注册,注册了就绑定,没注册就弹出提示
            wx.request({
              method: "POST",
              url: "https://xxx.cn/api-uaa/acl/wx/binding-ma",
              data: { mobile: res.data.wxMaPhoneNumberInfo.purePhoneNumber, unionId },
              success: result => {
                //绑定成功
                if (result.data.code == 0) {
                  wx.request({
                    method: "POST",
                    url: "https://xxx.cn/api-uaa/oauth/token",
                    header: {
                      "content-type": "application/x-www-form-urlencoded",
                      Authorization: "Basic xxxxx="
                    },
                    data: { unionId, grant_type: "union_id", uuid },
                    success: response => {
                      wx.hideLoading()
                      //登录成功
                      if (response.data.code == 0) {
                        wx.hideLoading()
                        this.setData({
                          showPhone:false,
                          showSuccess: true
                        })
                      }
                      //uuid失效
                      else if (response.data.code == "-9355") {
                        wx.hideLoading()
                        wx.showToast({
                          title: '登录失效,等重新扫码登录',
                          icon: "none"
                        })
                      }
                      else {
                        wx.hideLoading()
                        wx.showToast({
                          title: '请求异常,请重新扫码',
                          icon: "none"
                        })
                      }
                    },
                    fail: error => {
                      wx.hideLoading()
                      wx.showToast({
                        title: '服务器繁忙~',
                        icon: "none"
                      })
                    },
                  })

                }
                //手机号未注册
                else if (result.data.code == -1) {
                  wx.hideLoading()
                  this.setData({
                    showPhone: false,
                    showNoRegister: true
                  })
                }
              },
              fail: error => {
                wx.hideLoading()
                wx.showToast({
                  title: '服务器繁忙~',
                  icon: "none"
                })
              },
            })
          }
        },
        fail: error => {
          wx.hideLoading()
          wx.showToast({
            title: '服务器繁忙~',
            icon: "none"
          })
        },
      })
    }
  },

  //得到地址栏的参数
  getParams(url){
    let num=url.indexOf("?")
    let params=url.substr(num+1)
    let arr=params.split("&")
    let kv = [];
    arr.forEach(r=>{
      let n = r.indexOf("=");
        let k = r.substring(0, n);
        let v = r.substr(n + 1);
        let obj = {};
        obj[k] = v;
        kv.push(obj);
    })
    return kv
  },
  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    wx.hideShareMenu()
    //在地址栏拿到uuid
    let url =decodeURIComponent(options.q) 
    let uuid = ""
    let arr=this.getParams(url)
    let obj = arr.find((r) => r.uuid);
    if (obj != undefined) {
      uuid = obj.uuid;
    }
    this.setData({
      uuid,
    })
    let tenantId = this.data.tenantId
    wx.showLoading({
      title: '加载中...',
    })
    //调用一次接口表示微信已经扫码,用来改变web端扫码状态
    wx.request({
      method: "GET",
      url: "https:/xxx.cn/api-uaa/acl/wx/qrcode/isScan",
      data: { uuid },
      success: result => {

      },
      fail: error => {
      },
    })
    wx.login({
      success: res => {
        //根据code换取unionId
        wx.request({
          method: "GET",
          url: "https://xxx.cn/api-uaa/acl/wx/check-code",
          data: { code: res.code, tenantId },
          success: result => {
            if (result.data.code == 0) {
              let { unionId } = result.data.data
              this.setData({
                unionId
              })
              wx.request({
                method: "POST",
                url: "https://xxx.cn/api-uaa/oauth/token",
                header: {
                  "content-type": "application/x-www-form-urlencoded",
                  Authorization: "Basic xxxxxx=="
                },
                data: { unionId, grant_type: "union_id", uuid },
                success: response => {
                  wx.hideLoading()
                  //用户已经绑定过用户,登录成功
                  if (response.data.code == 0) {
                    this.setData({
                      showSuccess: true
                    })
                  }
                  //用户未绑定账号
                  else if (response.data.code == "-9354") {
                    wx.showToast({
                      title: '您微信还未绑定账号,请先授权手机号绑定账号',
                      icon: "none"
                    })
                    this.setData({
                      showPhone: true
                    })
                  }
                  //uuid失效
                  else if (response.data.code == "-9355") {
                    wx.showToast({
                      title: '登录失效,等重新扫码登录',
                      icon: "none"
                    })
                  }
                  else {
                    wx.showToast({
                      title: '请求异常,请重新扫码',
                      icon: "none"
                    })
                  }
                },
                fail: error => {
                  wx.hideLoading()
                  wx.showToast({
                    title: '服务器繁忙~',
                    icon: "none"
                  })
                },
              })
            } else {
              wx.hideLoading()
              wx.showToast({
                title: '请求异常,请重新扫码',
                icon: "none"
              })
            }
          },
          fail: error => {
            wx.hideLoading()
            wx.showToast({
              title: '服务器繁忙~',
              icon: "none"
            })
          },
        })
      },
      error: res => {
        console.log("获取code失败")
      }
    });
  },


})

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/744586.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

springcloud笔记二

配置管理服务是共有的&#xff0c;结合微服务自身的配置。这样核心配置更改就无需逐个更改 配置管理: 首先新建一个配置管理 Data ID为配置文件的名称 一般为项目名称-项目环境yaml&#xff0c;如userservice-dev.yaml 编写配置内容&#xff0c;发布 获取nacos配置信息: 可能…

数据透视表:pivot_table()--Pandas

1. 函数功能 创建数据透视表&#xff0c;返回一个EXCEL形式的数据透视表。 2. 函数语法 DataFrame.pivot_table(valuesNone, indexNone, columnsNone, aggfuncmean, fill_valueNone, marginsFalse, dropnaTrue, margins_nameAll, observedFalse, sortTrue)3. 函数参数 参数…

Vue3 父子组件之间传值

Vue3TSVite环境开发 1.父组件给子组件传递方法&#xff0c;属性和值 父组件引入子组件处里面绑定方法 showBtn &#xff0c;属性name和值msg 子组件通过defineProps()来接收 子组件页面显示父组件的方法 showBtn &#xff0c;属性name和值msg 2.父组件接收子组件传递的…

ModaHub魔搭社区:向量数据库Zilliz Cloud的AUTOINDEX教程

目录 创建索引和向量搜索 总结 为满足用户不同需求,Zilliz Cloud 提供 3 种类型的集群 CU——性能型、容量型和经济型。但是,为不同类型 CU 集群中的 Collection 创建索引时,通常需要根据所选择的 CU 类型调整索引参数。为了方便您创建索引,免去调节参数的麻烦,Zilliz C…

Metasploit Pro 4.22.1-2023070501 (Linux, Windows) - 渗透测试框架

Metasploit Pro 4.22.1-2023070501 (Linux, Windows) - 渗透测试框架 Rapid7 Penetration testing 请访问原文链接&#xff1a;https://sysin.org/blog/metasploit-pro-4/&#xff0c;查看最新版。原创作品&#xff0c;转载请保留出处。 作者主页&#xff1a;sysin.org 世界…

投影矩阵公式推导

如下图所示&#xff1a; y对x投影记作yx&#xff0c;则&#xff1a; <yx, x> <yx z, x> |yx| * |x| yx |yx| * x / |x| <yx, x> / |x| *x / |x| &#xff0c;即可得到下图中的矩阵。 注意该矩阵的如下性质&#xff1a; p是对称的rank 1p^2 p QE分…

基于STM32CUBEMX驱动TOF模块VL6180与VL6180X(3)----修改设备地址

基于STM32CUBEMX驱动TOF模块VL6180与VL6180X----3.修改设备地址 概述修改设备地址主程序测试结果 概述 本章主要介绍如何修改VL6180X传感器的I2C地址&#xff0c;并成功驱动设备以使用新的地址。VL6180X是一种多功能、高性能的接近和环境光传感器&#xff0c;常用于测量物体与…

如何在海外进行A/B测试

A/B测试是对应用的各个版本进行实验&#xff0c;以分析用户如何与其交互的有效过程&#xff0c;它能够帮助我们改进关键指标&#xff0c;例如参与度或应用内购买&#xff0c;以及推出新功能&#xff0c;从而最大限度地降低大规模流失用户的风险。 A/B测试和ASO优化通常适用于应…

唐僧的项目总结报告,我是真服了

早上好&#xff0c;我是老原。 上个月给大家更新了一篇项目管理案例——西天取经。 由于该项目的亏损必须要裁掉团队中的其中一人&#xff0c;究竟该裁掉谁&#xff0c;大家也是讨论的非常激烈&#xff0c;各有各的建议。 鉴于项目已经成功交付&#xff0c;唐僧作为这个项目…

基于51单片机和proteus的智能加湿器设计

此系统是基于51单片机和proteus的仿真设计&#xff0c;功能如下&#xff1a; 1. LCD1602实时显示环境温湿度。 2. 系统分为自动/手动模式&#xff0c;自动模式下系统根据读取的湿度值和设定的湿度值自动运行&#xff0c; 手动模式下使用按键启动/停止设备。 3. 湿度阈值可通…

基于 jmeter 和 shell 的接口性能自动化

目录 前言&#xff1a; 1. 总体需求 2. 实现流程 3.准备工作 4.具体实现 4.1 用例执行 主流程脚本 4.2 服务器监控 监控脚本&#xff1a; 服务器监控脚本 4.3 生成 html 报告 html 样式表 发邮件脚本 前言&#xff1a; 基于JMeter和Shell的接口性能自动化是一种有…

SpringBoot 项目使用 Redis 对用户IP进行接口限流

本文主要参考了该篇文章&#xff1a;https://www.zhihu.com/question/586213782/answer/3038040317?utm_id0 文章目录 一、思路1.1 固定时间段&#xff08;旧思路&#xff09;1.1.1 思路描述1.1.2 思路缺陷 1.2 滑动窗口&#xff08;新思路&#xff09;1.2.1 思路描述1.2.2 Re…

ELK 企业级日志分析系统(二)

ELK 一、FilebeatELK 部署二、logstash的使用grok正则捕获插件mutate 数据修改插件multiline 多行合并插件date 时间处理插件 一、FilebeatELK 部署 Node1节点&#xff08;2C/4G&#xff09;&#xff1a;node1/192.168.136.52 Elasticsearch Node2节点&#xff08;2C/4G&#…

第7集丨JavaScript 中函数——概述

目录 一、函数概览二、函数定义2.1 函数声明 (函数语句)2.2 函数表达式 (function expression)2.3 匿名函数立即执行2.4 函数生成器声明 (function* 语句)2.5 函数生成器表达式 (function*表达式)2.6 箭头函数表达式 (>)2.7 Function构造函数2.8 生成器函数的构造函数 三、函…

C#实现将小数值四舍五入为整数

一、需求说明 在项目的开发中&#xff0c;遇到一些除法计算内容会产生小数值&#xff0c;但是又需要根据项目的实际情况将这些小数内容化为整数&#xff0c;方便后续内容的实现。 二、需求分析 将小数内容转为整数【但是转为小数又分为几种情况】&#xff1a; ①将小数取为下…

银河麒麟服务器v10 sp1 部署 mysql 客户端工具 DBeaver

上一篇&#xff1a;银河麒麟服务器v10 sp1 安装mysql_csdn_aspnet的博客-CSDN博客 DBeaver 是数据库管理器的客户端&#xff0c;它允许以舒适的方式管理数据库实例的数据和选项。DBeaver 支持任何具有 JDBC 驱动程序的数据库 – MySQL/MariaDB、PostgreSQL、Oracle、DB2 LUW、…

性能测试工具 Loadrunner 和 Jmeter 测试结果大 PK

目录 前言&#xff1a; 测试一&#xff1a;1 个用户陆续执行登录操作&#xff0c;迭代 100 次&#xff0c;运行完就结束 测试二&#xff1a;50 个用户并发执行登录操作&#xff08;有集合点&#xff09; 前言&#xff1a; 性能测试工具LoadRunner和JMeter都是流行的工具&am…

ASP.net 配置CSP

ASP.net 开启全局CSP配置 <add name"Content-Security-Policy" value"default-src self; script-src self unsafe-inline unsafe-eval http://seal.digicert.com; style-src self unsafe-inline;" />在web.config中添加该行配置即可 配置完成后&am…

Im6ull 系统移植之 命令行

一 系统移植 系统移植 主要分四个不分由系统启动流程决定 U-Boot的移植 Linux内核的移植 根文件系统的构建系统烧写 1.1 交叉编译环境 交叉编译器有很多种&#xff0c;我们使用 Linaro 出品的交叉编译器&#xff0c; Linaro 是一间非营利性质的开 放源代码软件工程公…

LeetCode[11]盛水最多的容器

难度&#xff1a;Medium 题目&#xff1a; 给定一个长度为 n 的整数数组 height 。有 n 条垂线&#xff0c;第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。 找出其中的两条线&#xff0c;使得它们与 x 轴共同构成的容器可以容纳最多的水。 返回容器可以储存的最大水量。 …