前面博客我有写微信扫码跳转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失败")
}
});
},
})