最近使用腾讯云时,用的都是微信扫码登入,发现会跳转到腾讯云助手小程序进行确认登入。感觉挺好用的,就想做一个扫码登入。
实现原理:
1.匿名登入
进入腾讯云云开发控制台,在登入授权选项下,开启匿名登入
2.安全域名配置
3.在数据库选项下,新建 user 集合,进入详情页,进行权限设置
{
"read": "doc._openid == auth.openid||doc.uid == auth.uid",
"write": "doc._openid == auth.openid||doc.uid == auth.uid"
}
4.新建 index.html 页面
主要更能:点击微信登入后,调用 weblogin 云函数,获取小程序码,并渲染到页面。根据uid,监听 user 集合,当用户在小程序登入后,把用户的信息渲染到页面。
<!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 ,并生成带参数的小程序码
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 文件中,添加以下模块
{
"dependencies": {
"@cloudbase/node-sdk": "^2.7.1",
"axios": "^0.21.1",
"wx-server-sdk": "~2.5.3"
}
}
新建 userInfo 云函数
主要功能:管理用户信息,查询、添加和更新
// 云函数入口文件
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 文件中添加以下模块
{
"dependencies": {
"wx-server-sdk": "~2.5.3",
"tcb-router": "latest"
}
}
新建 login 页面
在 login.wxml 文件中,渲染用户信息
<!--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 文件中,编写业务逻辑
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 删除。