主要是对app.js代码部分的学习笔记
一、检查是否登录
1.无token
----》跳转登录页
2.有token
token无效----》清除token+跳转登录授权页(authorize)
// 判断是否登录
let token = wx.getStorageSync('token');
// 没有token
if (!token) {
that.goLoginPageTimeOut()
return
}
// 有token
wx.request({
url: that.globalData.subDomain + '/user/check-token',
data: {
token: token
},
success: function (res) {
// 有token,但是无效
if (res.data.code != 0) {
wx.removeStorageSync('token')
that.goLoginPageTimeOut()
}
}
})
// 回到登录页
goLoginPageTimeOut: function () {
setTimeout(function(){
wx.navigateTo({
url: "/pages/authorize/index"
})
}, 1000)
},
二、授权登录页面
对应的页面路径pages/autgorize
获取信息按钮(加上open-type和bindgetuserinfo):
<button open-type="getUserInfo" bindgetuserinfo="bindGetUserInfo" class="save-btn">授权登录</button>
点击事件:
bindGetUserInfo: function (e) {
// 若获取用户信息,则返回
if (!e.detail.userInfo){
return;
}
// 网络已连接,则将userInfo存入缓存,并且登录
if (app.globalData.isConnected) {
wx.setStorageSync('userInfo', e.detail.userInfo)
this.login();
} else {
wx.showToast({
title: '当前无网络',
icon: 'none',
})
}
}
传入的e打印出来:
登录代码:
// 登录
login: function () {
let that = this;
let token = wx.getStorageSync('token');
if (token) {
// 先检查token
wx.request({
url: app.globalData.subDomain + '/user/check-token',
data: {
token: token
},
success: function (res) {
if (res.data.code != 0) {
wx.removeStorageSync('token')
that.login();
} else {
// 回到原来的地方放
wx.navigateBack();
}
}
})
return;
}
// 调用login的API
wx.login({
success: function (res) {
wx.request({
url: app.globalData.subDomain + '/user/wxapp/login',
data: {
code: res.code
},
success: function (res) {
console.log(res);
if (res.data.code == 10000) {
// 去注册
that.registerUser();
return;
}
if (res.data.code != 0) {
// 登录错误
wx.hideLoading();
wx.showModal({
title: '提示',
content: '无法登录,请重试',
showCancel: false
})
return;
}
// 用返回的res的data中的token重新缓存
wx.setStorageSync('token', res.data.data.token)
wx.setStorageSync('uid', res.data.data.uid)
// 回到原来的地方
wx.navigateBack();
}
})
}
})
}
从本地取token
- 如果存在,就去调用后端的
/user/check-token
接口去验证 - 如果不存在,就执行微信的
wx.login()
详细看 参考的开发文档
三、小结
1.先通过token判断是否登录
- 未登录---->去授权页
- 登录了---->调用/user/check-token检查token是否有效
- 无效---->移除token+去授权页
2.授权页(点击授权按钮,触发bindGetUserInfo事件)
1.先拿到userInfo
2.判断网络是否连接
- 连接了---->将userInfo放入缓存,并且login()
- 未连接---->showToast
3.login()部分
检查token
成功---->wx.navigateBack();
失败---->remove token+重新wx.login()
wx.login()获取token+uid存入缓存,回到上一页
1.调用 wx.login()
获取 临时登录凭证 code
,有效期为 5分钟;(临时登录凭证 code
只能使用一次)
2.将临时 code
使用wx.request
传到后端,后端调用 auth.code2Session
接口,换取用户唯一标识 OpenID
和 会话密钥 session_key
(我们需要获得的是uid+token);( openid
是用户唯一标识,session_key
能保证当前用户进行会话操作的有效性)
注意:
获取session_key
出于安全性的考虑,要在后端调用。如果我们在前端通过 request调用此接口,就不可避免的需要将我们小程序的appid
、secret
和服务端下发的session_key
暴露在外部,会给我们的业务安全带来极大的风险。
session_key
拥有一定的时效性。用户越久未使用小程序,用户登录态越有可能失效。反之如果用户一直在使用小程序,则用户登录态一直保持有效。具体时效逻辑由微信维护,对开发者透明。开发者需要调用wx.checkSession
接口检测当前用户登录态是否有效。
3.后端自定义新的密钥并关联返回的 session_key
和 openid
(我们需要获得的是uid+token)**,返给前端,前端将其存储在 storage 中。(会话密钥 session_key
是对用户数据进行 密签名的密钥。为了应用自身的数据安全,开发者服务器不应该把会话密钥下发到小程序,也不应该对外提供这个密钥,所以要定义新的密钥)。
之所以存在storage中,是因为小程序没有 cookie,相应的后端 set-cookie 在小程序中不起作用。
四、可能遇到的问题
在接口报401错误时,对其做登录处理,登录成功后再次调用接口。这种情况下,多接口并行就会出现问题。
因为多接口都会调 wx.login 获取 code 后再调后端的登录接口,而登录凭证 code 只能使用一次,这时候后端对多接口就会接收到不同的 code,返回的自定义密钥就会有多个,不能保持统一。
处理的方案
是后端在一定时间内对用户自定义登录态做缓存。接口调 wx.login 获取 code 后再调后端的登录接口时,判断后端缓存中有无此用户,如果没有,返回新的密钥,如果缓存中存在此用户并在缓存有效时间内,就查找并返回之前的密钥。