前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >微信小程序实现扫码登录网站

微信小程序实现扫码登录网站

原创
作者头像
王秀龙
修改2021-09-09 17:48:47
7K3
修改2021-09-09 17:48:47
举报
文章被收录于专栏:云开发分享云开发分享

最近使用腾讯云时,用的都是微信扫码登入,发现会跳转到腾讯云助手小程序进行确认登入。感觉挺好用的,就想做一个扫码登入。

实现原理:

  1. 打开网站,使用云开发,进行匿名登入
  2. 用户点击微信登入,调用云函数,获取匿名用户uid,并生成一个带参数 uid 的小程序码
  3. 用户微信扫码进入小程序,获取 uid 并和用户_openid 进行绑定
  4. web 端通过 uid 获取用户信息,小程序端通过_openid 获取用户信息

web端

1.匿名登入

进入腾讯云云开发控制台,在登入授权选项下,开启匿名登入

匿名登入
匿名登入

2.安全域名配置

安全配置
安全配置

3.在数据库选项下,新建 user 集合,进入详情页,进行权限设置

权限设置
权限设置
代码语言:txt
复制
{
  "read": "doc._openid == auth.openid||doc.uid == auth.uid",
  "write": "doc._openid == auth.openid||doc.uid == auth.uid"
}

4.新建 index.html 页面

主要更能:点击微信登入后,调用 weblogin 云函数,获取小程序码,并渲染到页面。根据uid,监听 user 集合,当用户在小程序登入后,把用户的信息渲染到页面。

代码语言:txt
复制
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8" />
    <title>小程序扫码登录</title>
</head>

<body>
    <div class="contain">
        <h2>小程序扫码登录</h2>
        <button type="button" onclick="getQRCode()" id="button">微信登入</button>
        <div id="avatar"></div>
        <div id="qrcode"></div>
    </div>

    <script src="//imgcache.qq.com/qcloud/cloudbase-js-sdk/1.5.0/cloudbase.full.js"></script>
    <script>
        const app = cloudbase.init({
            env: "ww"   // 此处填入你的环境ID
        });
        const auth = app.auth();
        async function login() {
            await auth.anonymousAuthProvider().signIn();
            // 匿名登录成功检测登录状态isAnonymous字段为true
            const loginState = await auth.getLoginState();
            console.log(loginState.isAnonymousAuth); // true
        }
        login();

        //调用云函数,获取带参数的小程序码
        async function getQRCode() {
            const result = await app.callFunction({ name: "weblogin" })

            const { uid, fileId } = result.result;

            const linkresult = await app.getTempFileURL({
                fileList: [fileId]
            })
            const QRCodeUrl = linkresult.fileList[0].tempFileURL;
            window.uid = uid;
            window.QRCodeUrl = QRCodeUrl;
            const qrcodeimg = document.createElement('img');
            qrcodeimg.src = QRCodeUrl;
            document.getElementById('qrcode').appendChild(qrcodeimg);
            interval();
        }

        //获取用户信息
        async function getUserInfo() {
            const uid = window.uid;
            const userInfo = await app
                .database()
                .collection("user")
                .where({
                    uid: uid,
                })
                .get();
            console.log("获取到的用户信息", userInfo);
            return userInfo;
        }

        // 监听集合中符合查询条件的数据的更新事件
        const interval = async function () {
            const watcher = await app
                .database()
                .collection("user")
                .where({
                    uid: uid
                })
                .watch({
                    onChange: async function (snapshot) {

                        const userData = await getUserInfo();
                        if (userData.data.length != 0) {
                            const { avatarUrl, city, nickName } = userData.data[0];
                            document.getElementById('qrcode').style.visibility = 'hidden';
                            document.getElementById('avatar').innerHTML = `<img width="100" height="100" src="${avatarUrl}"><br>${nickName}<br>${city}`;

                            document.getElementById("button").style.visibility = "hidden";
                            document.getElementById("qrcode").style.visibility = "hidden";
                        }
                    },
                    onError: function (err) {
                        console.error("the watch closed because of error", err);
                    },
                });
        };
    </script>
</body>

</html>

云函数

新建 weblogin 云函数

主要功能:获取匿名登入用户的 uid ,并生成带参数的小程序码

代码语言:txt
复制
const cloud = require('wx-server-sdk')
cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV });
const tcb = require("@cloudbase/node-sdk")

const app = tcb.init({ env: cloud.DYNAMIC_CURRENT_ENV });
const auth = app.auth();

const axios = require('axios')
const APPID = "******"  //换成你的小程序appid
const APPSECRET= "******" //换成你的小程序key
exports.main = async (event, context) => {
  const { userInfo } = await auth.getEndUserInfo();
  console.log(userInfo);
  const {uid} = userInfo

    const tokenurl = `https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${APPID}&secret=${APPSECRET}`
    const res = await axios.get(tokenurl)
    const {access_token} = res.data

    const qrcodeurl=`https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=${access_token}`
    const wxacodeResult = await axios({
      method: 'post',
      url: qrcodeurl,
      responseType: 'arraybuffer',
      data: {
        scene:uid,
        page:"pages/login/login"
      }
    });

    const uploadResult = await cloud.uploadFile({
      cloudPath: `${uid}.jpeg`,
      fileContent: wxacodeResult.data
    })

    return {
      uid:uid,
      fileId:uploadResult.fileID
    }
}

在 package.json 文件中,添加以下模块

代码语言:txt
复制
{
  "dependencies": {
    "@cloudbase/node-sdk": "^2.7.1",
    "axios": "^0.21.1",
    "wx-server-sdk": "~2.5.3"
  }
}

新建 userInfo 云函数

主要功能:管理用户信息,查询、添加和更新

代码语言:txt
复制
// 云函数入口文件
const cloud = require('wx-server-sdk')
const TcbRouter = require('tcb-router');
cloud.init({
  // API 调用都保持和云函数当前所在环境一致
  env: cloud.DYNAMIC_CURRENT_ENV
})
const db = cloud.database()

// 云函数入口函数
exports.main = async (event, context) => {
  const wxContext = cloud.getWXContext()
  const app = new TcbRouter({
    event
  })
  const collection = "user" //数据库的名称

  app.use(async (ctx, next) => {
    ctx.data = {}
    await next();
  });

  app.router('checkUser', async (ctx, next) => {
    ctx.body = await db.collection(collection).where({
      _openid: wxContext.OPENID // 填入当前用户 openid
    }).get()
  })

  app.router('addUser', async (ctx, next) => {
    ctx.body = await db.collection(collection)
      .add({
        data: {
          _openid: wxContext.OPENID,
          ...event.data
        }
      })
  })

  app.router('updateUser', async (ctx, next) => {
    ctx.body = await db.collection(collection).where({
      _openid: wxContext.OPENID
    }).update({
      data: {
        uid: event.uid
      },
    })
  })

  return app.serve();
}

在 package.json 文件中添加以下模块

代码语言:txt
复制
{
  "dependencies": {
    "wx-server-sdk": "~2.5.3",
    "tcb-router": "latest"
  }
}

小程序端

新建 login 页面

在 login.wxml 文件中,渲染用户信息

代码语言:txt
复制
<!--pages/login/login.wxml-->
<view class="container">
    <open-data type="userAvatarUrl"></open-data>
    <open-data type="userNickName"></open-data>
    <view class="padding-xl margin-top-xl" wx:if="{{!isLogin}}">
      <button bindtap="getUserProfile"> 确认登入</button>
    </view>
    <view class="padding-xl margin-top-xl" wx:if="{{isLogin}}">
      <text> 你已经成功登入!</text>
    </view>
</view>

在 login.js 文件中,编写业务逻辑

代码语言:txt
复制
Page({

  /**
   * 页面的初始数据
   */
  data: {
    hasUser: 0,
    uid: '',
    isLogin: false
  },

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    this.checkUser()
    if (options.scene) {
      const scene = decodeURIComponent(options.scene)
      this.setData({
        uid: scene
      })
    }
  },

  /**
   * 调用云函数--查询数据库有没有该用户
   */
  checkUser() {
    wx.cloud.callFunction({
      name: 'userInfo',
      data: {
        $url: "checkUser"
      }
    }).then(res => {
      this.setData({
        hasUser: res.result.data.length
      })
    }).catch(console.error)
  },

  getUserProfile() {
    wx.showLoading({
      title: '加载中',
    })
    if (this.data.hasUser) {
      wx.cloud.callFunction({
        name: 'userInfo',
        data: {
          $url: "updateUser",
          uid: this.data.uid
        },
      }).then(res => {
        this.setData({
          isLogin: true
        })
        wx.showToast({
          title: '登入成功',
          icon: 'success',
          duration: 2000
        })
      }).catch(console.error)
    } else {
      const that = this;
      wx.getUserProfile({
        desc: '展示用户信息', // 声明获取用户个人信息后的用途,后续会展示在弹窗中,请谨慎填写
        success: (res) => {
          wx.cloud.callFunction({
            name: 'userInfo',
            data: {
              $url: "addUser",
              data: {
                uid: that.data.uid,
                ...res.userInfo
              }
            },
          }).then(res => {
            console.log(res.result)
            this.setData({
              isLogin: true
            })
            wx.showToast({
              title: '登入成功',
              icon: 'success',
              duration: 2000
            })
          }).catch(console.error)
        }
      })
    }
  }
})

最终实现效果

扫码登入
扫码登入

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • web端
  • 云函数
  • 小程序端
  • 最终实现效果
相关产品与服务
云开发 CloudBase
云开发(Tencent CloudBase,TCB)是腾讯云提供的云原生一体化开发环境和工具平台,为200万+企业和开发者提供高可用、自动弹性扩缩的后端云服务,可用于云端一体化开发多种端应用(小程序、公众号、Web 应用等),避免了应用开发过程中繁琐的服务器搭建及运维,开发者可以专注于业务逻辑的实现,开发门槛更低,效率更高。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档