微信授权登录:Web端生成二维码,跳转微信小程序并确认授权,实现小程序和Web的同时登录(参照腾讯云)

微信授权登录:Web端生成二维码,跳转微信小程序并确认授权,实现小程序和Web的同时登录(参照腾讯云)

最近做了一个需求(效果部分参照腾讯云 https://cloud.tencent.com/),Web端生成二维码,跳转微信小程序并确认授权,实现小程序和Web的同时登录

一、预期效果(腾讯云)

首先扫web端的这个二维码

然后跳转对应的小程序,点击小程序中的确认登录后,调起授权成功后实现小程序和Web同时登录

二、梳理思路

因为跳转的是小程序页面,所以web端的码对应的是 小程序某页面 的二维码

若要实现小程序和Web的同时登录,web扫码后,

① 一定需要有一个“唯一信件”,从Web带到小程序(拼接在二维码中),在小程序中解析出来以后,登录时把它带给后端; ② web端要轮询去调后端的接口,并且是带着这个“唯一信件”,来询问这个“唯一信件”有没有在小程序中获得登录

这个过程就好像,小孩拿着身份证去学校报道,父母在家里持续打电话询问学校:身份证号为XX的小孩现在是否完成报道

在上一步的基础上,这个“唯一信件” 还存在一个过期时间,比如超过10分钟后就自动失效

从代码的角度来讲,这个“唯一信件” 应由后端生成,这样也方便后端去维护过期状态

至此,应该只剩下一个问题:web端的这个二维码,由前端还是后端生成?怎样生成?

三、关于web端的二维码

如果由前端生成,可以采用 扫普通链接二维码 打开小程序,根据官方给出的示例去配置,前端安装qrcodejs2插件生成二维码。

只需要注意一点:开发时只能采用对应的 测试链接 进行模拟(动态参数无法跳转),规则正式发布以后,才可以拿到动态参数

上面的这种方式,二维码的内容对应的是链接地址,所以是先跳转链接,然后再唤起小程序,从体验上来说,不是那么友好

并且上述过程中需要后端往服务器放校验文件、前端需要下载qrcode库,整体并不快捷

况且 后端调微信接口直接生成小程序码 的方式有很多种,功能场景也很完善(我这里后端采用的是wxacode.getUnlimited 这种)

有一点需要注意,后端生成的二维码是调微信接口拿的,所以对应的是线上小程序的版本

对比下来,后端来生成,开发过程更清晰、开发时间成本也更低、后续也更好维护

四、前端代码实现

前端代码实现——web篇

您的二维码已失效

请点击下方刷新按钮

请使用微信扫一扫登录

刷新

.main {

width: 384px;

height: 300px;

background: #fff;

margin-top: 100px;

}

#login_container_wechat {

width: 200px;

height: 200px;

display: inline-block;

display: flex;

justify-content: center;

margin: 30px auto;

position: relative;

}

.timeout-cover {

position: absolute;

width: 100%;

height: 100%;

left: 0;

top: 0;

display: flex;

flex-direction: column;

align-items: center;

justify-content: center;

background: rgba(255, 255, 255, 0.9);

color: rgb(245, 59, 59);

}

#login_container_wechat img {

width: 200px;

height: 200px;

background: #f5f5f5;

}

data () {

return {

// 微信登录定时器

wechatTimer: null,

// 微信登录定时器倒计时

wechatTimerCount: 0,

// 微信登录二维码

qrCode: undefined,

// 微信登录唯一标志

qToken: undefined,

// 微信登录二维码是否超时

timeOut: false

}

},

mounted () {

// 初始化微信二维码,带上邀请码

this.getLoginWxQrCode()

},

// 获取绑定二维码

getLoginWxQrCode () {

getLoginWxQrCodeApi().then(res => {

const { code, data, msg } = res

if (code === 0) {

// 超时状态重置

this.timeOut = false

// 二维码、唯一标志QToken

this.qrCode = data.QCode

this.qToken = data.QToken

// 轮询,获取小程序微信登录结果

this.wechatTimer = setInterval(() => {

this.getWechatLoginResult()

// 定时器累加

this.wechatTimerCount = this.wechatTimerCount + 1

// 超过一分钟,清除定时器

if (this.wechatTimerCount > 180) {

this.clearWechatTimer()

}

}, 1000)

} else {

this.$message.error(msg)

}

})

},

// 获取微信授权结果

getWechatLoginResult () {

getQrCodeStatusApi({

QToken: this.qToken

}).then(res => {

const { code, data } = res

if (code === 0) {

// [status]: -1过期 0二维码正常 1已被扫描 2已被操作(成功或失败)

const status = data.status

if (status === 0) {

console.log('二维码状态正常')

} else if (status === 1) {

console.log('二维码已被扫描')

} else if (status === 2) {

console.log('二维码操作了')

// 关闭定时器

this.clearWechatTimer()

// 拿到token

if (data.token) {

// 在这里实现web登录

}

} else if (status === -1) {

console.log('二维码过期了')

this.timeOut = true

this.clearWechatTimer()

}

}

})

},

// 刷新二维码

refreshCode () {

// 清除微信定时器

this.clearWechatTimer()

this.getLoginWxQrCode()

},

// 清除微信定时器

clearWechatTimer () {

clearInterval(this.wechatTimer)

this.wechatTimerCount = 0

},

web端效果:

前端代码实现——小程序

扫码进入小程序,在对应页面的 onLoad 中拿到链接里拼接的参数

先看下后端使用 wxacode.getUnlimited 的二维码内容:

page,是小程序的落地页,需要在前面生成web端二维码时给到后端scene 是二维码中的参数载体,我们在小程序中,取的就是这个参数重要的是,在真机中,参数scene有可能被编码,需要兼容这个现象跳转到这个页面后,我们需要重新走一遍小程序的授权登录(不管当前是否已经登录)

知道了上面这些前提,就可以码起来了

将使用微信登录XX平台

取消

.common-login-main {

padding-top: 200rpx;

}

.mytop-box {

display: flex;

width: 100%;

height: 100%;

align-items: center;

flex-direction: column;

justify-content: center;

}

.mytop-avatar {

overflow: hidden;

width: 130rpx;

height: 130rpx;

left: 50%;

border-radius: 50%;

box-shadow: 3px 3px 10px rgba(0, 0, 0, 0.2);

}

.mytop-username {

font-size: 35rpx;

color: #3E3E40;

margin-top: 40rpx;

}

.desc {

font-size: 28rpx;

color: var(--descColor);

margin-top: 40rpx;

}

.btn {

margin-top: 80rpx;

width: 520rpx;

height: 72rpx;

line-height: 72rpx;

background-color: #FA7627;

color: #fff;

font-size: 28rpx;

border-radius: 36rpx;

margin-bottom: 40rpx;

}

.cancle {

text-align: center;

color: #FA7627;

font-size: 28rpx;

}

onLoad(options) {

// 开发时可以在这里重置数据用来测试,如:options.scene = 's=1632824497386&test=123'

// scene中参数有可能是多个,这个开发时也需要考虑进去

// 将场景值转为object,并兼容转码或不转码

if (options.scene) {

var scene = {}

// 含有%3D,手动转换一下

if (options.scene.includes('%3D')) {

scene = JSON.parse(

'{"' +

decodeURI(

decodeURIComponent(options.scene)

.replace(/&/g, '","')

.replace(/=/g, '":"')

) +

'"}'

)

} else {

let sceneArr = options.scene.split('&')

sceneArr.forEach(item => {

scene[item.split('=')[0]] = (item.split('=')[1])

})

}

}

// 将扫描成功状态告诉后端(如果 web端不需要展示是否已被扫描,这一步可以省略)

updateWxQTokenInfoAPI({ scene.QToken })

this.setData({

query: scene

})

},

// 点击确认登录(正常的走微信登录)

getUserProfile () {

wx.showLoading()

var p1 = new Promise(function (resolve, reject) {

wx.login({

success: res => {

resolve(res)

}

})

})

var p2 = new Promise(function (resolve, reject) {

wx.getUserProfile({

desc: '用于完善会员资料',

success: res => {

resolve(res)

},

fail: err => {

wx.hideLoading()

}

})

});

// 同时执行p1和p2,并在它们都完成后执行then:

Promise.all([p1, p2]).then((results) => {

// results是一个长度为2的数组,放置着p1、p2的resolve

this.handleUserInfo({

// 这里也可以选择性返回需要的字段

...results[0],

...results[1]

})

},

// 组织好后端需要的字段,并调用接口

handleUserInfo (data) {

const { code, encryptedData, userInfo, iv, rawData, signature, cloudID } = data

const params = {

// 这个登录时带过去,web端轮询就可以拿到已登录的状态了

QToken: this.data.query.QToken

// ....

}

// 调用接口维护本地登录态

}

实际效果: 实现下来会发现代码并不难,主要是前面的构思阶段要考虑

欢迎评论,一起探索更多~

相关推荐

“小牛资本(小牛在线)”最新公告,还有二次退赔?
365网站客服电话

“小牛资本(小牛在线)”最新公告,还有二次退赔?

📅 07-07 👁️ 7115
cf到v5要氪多少?(cfm到v5需要多少钱)
365网站客服电话

cf到v5要氪多少?(cfm到v5需要多少钱)

📅 07-14 👁️ 7303
Windows 11 总是在手动锁屏1分钟后息屏(关闭显示器)
365网站客服电话

Windows 11 总是在手动锁屏1分钟后息屏(关闭显示器)

📅 08-18 👁️ 8194