通常的登录都是通过一个表单,这很正常,但如果在小程序里你也这么做那就有点不可思议了,微信的一键登录对用户体验有多好你难道不知道?最主要——你要利用微信的生态必须需要用微信的登录,以获取相关信息来和微信交互。用户在小程序、小游戏中需要点击组件后,才可以触发登录授权弹窗、授权自己的昵称头像等数据。友情提示一下:wx.login并不需要点击组件,需要的是wx.getUserInfo,但通常我们都会用到UnionID、encryptedData、iv等信息完成完整的登录流程。
怎么在需要的页面都能弹出登录按钮,应该很多人都能想到:抽离出组件,那怎么保证在需要的页面都有这个组件呢?错杀一千也不能放过一个!把登录组件集成到共用的父组件,然后在每个页面都使用。我也建议这么做,因为这个共用的父组件其实又很多用处,例如iPhoneX适配等,在哪里校验是否需要鉴权。 官方的这张图已经做了很详尽的说明,但是看到session_key了吗?
会话密钥 session_key 有效性 开发者如果遇到因为 session_key 不正确而校验签名失败或解密失败,请关注下面几个与 session_key 有关的注意事项。 wx.login 调用时,用户的 session_key 可能会被更新而致使旧 session_key 失效(刷新机制存在最短周期,如果同一个用户短时间内多次调用 wx.login,并非每次调用都导致 session_key 刷新)。开发者应该在明确需要重新登录时才调用 wx.login,及时通过 code2Session 接口更新服务器存储的 session_key。 微信不会把 session_key 的有效期告知开发者。我们会根据用户使用小程序的行为对 session_key 进行续期。用户越频繁使用小程序,session_key 有效期越长。
开发者在 session_key 失效时,可以通过重新执行登录流程获取有效的 session_key。使用接口 wx.checkSession可以校验 session_key 是否有效,从而避免小程序反复执行登录流程。 当开发者在实现自定义登录态时,可以考虑以 session_key 有效期作为自身登录态有效期,也可以实现自定义的时效性策略。 怎么保证session_key的有效性 要保证调用接口时后端session_key不失效,只能在每次调用前先使用wx.checkSession检查是否有效 实践中也发现wx.checkSeesion非常耗时,大约200ms,所以也不能每次接口调用前都使用wx.checkSession检查是否有效 同时要注意前端不能随便重新执行wx.login,因为可能导致正在进行的其它后端任务session_key失效
得知:在使用小程序期间session_key是不会失效的。1、在每个请求前去校验有效性;2、将校验有效性的结果存储起来;3、通过async/await和刚才存储起来的结果来保证不过多调用wx.checkSession。 因为storage是永久的存储,而session_key的有效期却只是在使用小程序期间,所以你需要在小程序结束后手动重置该状态以重新校验其有效性,那是不是在app的onUnload里重置呢?不是!开发过小程序的应该都知道,那就是结束使用小程序的方式太多,不能保证每种方式都会触发onUnload,例如用户直接销毁了微信进程那用什么呢?直接用内存啊,借助内存的自动管理来智能管理,所以最终代码应该是这样的。 - // doRequest.js
- let wxSessionValid = null // 微信session_key的有效性
- // 带鉴权的请求封装
- async function doRequestWithCheckAuth() {
- ...
- if (typeof wxSessionValid !== 'boolean') {
- wxSessionValid = await checkWxSession() // 检查微信session是否有效
- }
- if (!wxSessionValid) {
- await reLogin() // 重新登录
- }
- wxSessionValid = true // 重新登陆后session_key一定有效
- ...
- }
复制代码怎么校验完整的认证体系:校验微信端的session_key略有麻烦,但不应该把它抛给服务端;服务端不能直接校验session_key的有效性而是通过调用接口发现错误了才知道失效了,这是被动的;服务端需要同时维护两个session。而放在前端我们只需要校验两个session的有效性即可,任何一个失效就重新登录,这是积极主动有效的操作,应该被提倡。 基本上梳理的差不多了,就差弹登录按钮了,这个简单,调用刚才封装的组件的方法就行了嘛,bingo,可是,点完允许后呢?怎么继续用户的操作呢?怎么能让用户的体验不被打断呢?先回放下刚才reLogin的代码 - async function reLogin() {
- // 确保有用户信息
- await new Promise(resolve => { // ⚠️注意开头有await!!!
- wx.getSetting({
- success: (res) => {
- // 如果用户没有授权或者没有必要的用户信息
- if (!res.authSetting['scope.userInfo'] || !_.isRealTrue(wx.getStorageSync('userInfoRes').userInfo)) {
- navToLogin(resolve) // 去提示用户点击登录按钮,⚠️注意:并把当前的resolve带过去
- } else {
- resolve() // 静默登录
- }
- }
- })
- })
- return new Promise((resolve) => {
- wx.login({
- success: res => {
- login(res.code).then((jwt) => {
- resolve(jwt) // resolve jwt
- }) // 通过code进行登录
- },
- fail(err) {
- wx.showToast({
- title: err.errMsg,
- icon: 'none',
- duration: 2000
- })
- }
- })
- })
- }
- function navToLogin(resolve) {
- /* eslint-disable no-undef */
- const pages = getCurrentPages()
- const page = pages[pages.length - 1] // 当前page
- page.openLoginModal(resolve) // 打开登录按钮弹框,并把当前的resolve带过去
- }
复制代码通过回调的方式当用户同意授权了就继续余下的逻辑,如果被拒绝了,则安利他,再拒绝就终止操作,下次需要授权也会继续弹出授权。 |