优雅解决微信小程序授权登录需要button触发
聊一聊最近的一个项目,这个项目是一个收书、售书的小程序,有商城、专栏、信息发布论坛等功能。虽然不是面向所有用户,但要求无论用户是否授权都皆可使用,但同时也要求部分功能对不授权的用户限制开放。
问题总结如下
- 首先是小程序不授权也可以使用,但是只有部分功能可用,比如浏览
- 第二问题是在用户想进一步使用小程序时需要获取用户授权
- 获取到用户授权的时候该如何处理跳转
解决方案
1.首先用户进入小程序的时候会在app.js中的onLaunch
发起登陆
微信小程序文档这样说
调用 wx.login() 获取 临时登录凭证code ,并回传到开发者服务器。
调用 code2Session 接口,换取 用户唯一标识 OpenID 和 会话密钥 session_key。
之后开发者服务器可以根据用户标识来生成自定义登录态,用于后续业务逻辑中前后端交互时识别用户身份。
也就是说服务器可以返回一个自定义的session,缓存后用于后续业务逻辑中前后端交互时识别用户身份
同时微信小程序文档也说了
1.wx.login 调用时,用户的 session_key 可能会被更新而致使旧 session_key 失效(刷新机制存在最短周期,如果同一个用户短时间内多次调用 wx.login,并非每次调用都导致 session_key 刷新)。开发者应该在明确需要重新登录时才调用 wx.login,及时通过 code2Session 接口更新服务器存储的 session_key。
2.微信不会把 session_key 的有效期告知开发者。我们会根据用户使用小程序的行为对 session_key 进行续期。用户越频繁使用小程序,session_key 有效期越长。
3.开发者在 session_key 失效时,可以通过重新执行登录流程获取有效的 session_key。使用接口 wx.checkSession可以校验 session_key 是否有效,从而避免小程序反复执行登录流程。
当开发者在实现自定义登录态时,可以考虑以 session_key 有效期作为自身登录态有效期,也可以实现自定义的时效性策略。
意思说没必要每次启动小程序都要登录,我这里使用的是每次启动都要登录
onLaunch: function () {
wx.login({
success: res => {
if (res.code) {
// 发送 res.code 到后台换取 openId, sessionKey
}else{
console.log('获取用户登录态失败:' + res.errMsg)
}
}
})
2.然后再通过wx.getSetting
判断用户是否已经授权过了,如果授权过了则可以直接调用 getUserInfo 获取头像昵称,不会弹框,存入globalData,那么该用户可以进行所有的操作。同时可以将 res 发送给后台解码出 unionId。
wx.getSetting({
success: res => {
if (res.authSetting['scope.userInfo']) {
// 已经授权,可以直接调用 getUserInfo 获取头像昵称,不会弹框
wx.getUserInfo({
success: res => {
// 可以将 res 发送给后台解码出 unionId
this.globalData.userInfo = res.userInfo
// 由于 getUserInfo 是网络请求,可能会在 Page.onLoad 之后才返回
// 所以此处加入 callback 以防止这种情况
if (this.userInfoReadyCallback) {
this.userInfoReadyCallback(res)
}
}
})
}
}
})
3.当小程序启动后,用户之前没有授权过的话,在使用发布信息、购物车、我的、论坛等功能的时候则跳转至提示用户授权页面或者使用弹窗提示用户授权,这个项目用的是页面。
注意: 因为用户授权之后要跳转到用户要使用的功能页面,所以要在重定向之前记录好用户当前的路径信息、要使用的功能的页面的路径信息,存储在globalData中,在获取授权后再重定向至该页面。 如果用户点击拒绝则返回原来页面
贴上部分代码
/**
* oldPath = getApp().globalData.oldPath
* 用户要用的功能页面
* newPath = getApp().globalData.goToPath
*/
const oldPath = getApp().globalData.oldPath
const newPath = getApp().globalData.goToPath
if (app.globalData.userInfo) {
goNewPath(newPath)
} else if (this.data.canIUse) {
// 由于 getUserInfo 是网络请求,可能会在 Page.onLoad 之后才返回
// 所以此处加入 callback 以防止这种情况
app.userInfoReadyCallback = res => {
if (e.detail.userInfo != void 0){
app.globalData.userInfo = res.userInfo
goNewPath(newPath)
}else{
goOldPath(oldPath)
}
}
} else {
// 在没有 open-type=getUserInfo 版本的兼容处理
wx.getUserInfo({
success: res => {
if (e.detail.userInfo != void 0){
app.globalData.userInfo = res.userInfo
goNewPath(newPath)
}else{
goOldPath(oldPath)
}
}
})
}
},
bindGetUserInfo: function (e) {
if (e.detail.userInfo != void 0){
app.globalData.userInfo = e.detail.userInfo
wx.switchTab({
url: '../bookcity/bookcity',
success: function (res) { },
fail: function (res) { },
complete: function (res) { },
})
}else{
// 授权失败
goOldPath(oldPath)
}
},
goNewPath: function(path){
// isTab()判断路径是否是Tab
if(isTab(path)){
wx.switchTab({
url: path,
success: function(res) {},
fail: function(res) {},
complete: function(res) {},
})
}else{
wx.reLaunch({
url: path ,
})
}
},
goOldPath: function(path){
wx.navigateBack({
delta: 1,
})
},
isTab: function(path){
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。