小程序静默登录与维护自定义登录态

马丁路德 等级 370 0 0

1.背景

在小程序中,openid是一个用户对于一个小程序/公众号的标识,开发者可以通过这个标识识别出用户,就如同你的身份证一样。

2.什么是静默登录?

在普通的应用中,用户通过表单验证登录建立用户体系,这种常见的登录方式一般是通过登录页面表单进行登录,对用户来说是有感的。

在小程序中,由于是基于微信,可以通过微信官方提供的API能力,使我们能够无感知得获取用户身份标识(openid),快速建立小程序内的用户体系,对用户来说是无感知的,因此是由程序来完成这个自动的登陆过程。

2.1登录流程时序

下图取自微信官方

小程序静默登录与维护自定义登录态

// 小程序端调用wx.login(),获取code并且上传到服务器
export async function doLogin() {
    if (isLogin) return false
    isLogin = true
    removeCache('token')
    const { code } = await wxp.login()
    const data = await login({ code })
    setCache('token', data.data.token)
    isLogin = false
    return true
}

// 服务端拿到code,调用auth.code2Session接口换取openid
const getOpenid = async function (appid, secret, code) {
    const resData = await axios.get('https://api.weixin.qq.com/sns/jscode2session?appid=' + appid + '&secret=' + secret + '&js_code=' + code + '&grant_type=authorization_code');
    return resData.data;
} 

总结流程:

  • 小程序端调用wx.login(),获取code并且上传到服务器
  • 服务器根据code,并且调用微信auth.code2Session接口换取openid
  • 后台服务器根据openid生成自定义token返回前端并且存储起来,后续业务逻辑用token来识别用户身份

3.如何维护自定义登录态

让我们来看下官方的处理方式:

小程序静默登录与维护自定义登录态

wx.checkSession({
  success () {
    //session_key 未过期,并且在本生命周期一直有效
  },
  fail () {
    // session_key 已经失效,需要重新执行登录流程
    wx.login() //重新登录
  }
}) 

由图中我们可以知道,真正决定登录态的是微信的checkSession接口。因此每次检查用户登录态是否有效就先调用一个checkSession接口,如果session_key失效,再发起登录流程。

4.静默登录整体流程

4.1app.onLaunch中发起登录

由于大部分的接口调用都需要token验证,因此在小程序启动的周期函数app.onLaunch中发起静默登录最为合适不过了。

小程序静默登录与维护自定义登录态

4.2处理小程序不支持异步阻塞

由于小程序的启动流程中,页面级和组件级的生命周期函数都不支持异步阻塞;因此会造成一个情况,app.onLaunch中发起的wx.login还没有成功的时候,页面级的生命周期函数已经向服务器发起请求。由于我们的接口设计大部分都是需要验证的,此时登录还未成功,token也还没有正确返回,因此页面级的生命周期发起的数据获取接口肯定是会报错的(例如返回了401)

4.2.1粗糙的方案

采用回调函数的方式

//app.js
this.globalData.wxp.showLoading({
        title: '登录中...'
      });
      await login();
      this.globalData.hasLogin = true;
      if (this.checkLoginReadyCallback) {
        this.checkLoginReadyCallback();
      }
      this.globalData.wxp.hideLoading();

页面的生命周期中
async onLoad() {
    if (app.globalData.hasLogin) {
    //如果已经登录了直接获取数据
      this.getUserInfo();
      this.getEvent();
    } else {
    //未登录定义下回调函数,等app.js登录成功之后进行调用
      app.checkLoginReadyCallback = async () => {
        this.getUserInfo();
        this.getEvent();
      };
    }
  }, 
  • 优点:简单粗暴
  • 缺点:代码结构差;如果是多个页面为启动页,则需要多个页面都定义回调函数(假设使用了小程序onShare模式)

4.2.2优雅的方式

借助fly.js库,实现对请求进行上锁机制。流程:app.js中发起登录,同时页面中也会发起请求。在请求拦截器中判断请求的接口是否为白名单(不需要token验证的接口)接口和token是否存在;如果都为false,锁住当前请求进入请求队列,执行登录流程。等待登录流程成功之后解锁请求队列,继续发起页面级的请求任务。如下为请求拦截器中的代码:

//拦截处理
fly.interceptors.request.use(async (request) => {
    //没有token且请求不是白名单的都锁住
    if (
        !getCache('token') &&
        !whiteList.some((item) => request.url.startsWith(item))
    ) {
        fly.lock()
        //去登陆 成功之后再unlock
        await doLogin()
        fly.unlock() //解锁后,会继续发起请求队列中的任务
    }

    if (getCache('token') && !fly.config.headers['Authorization']) {
        request.headers['Authorization'] = getCache('token')
    }
    request.headers['Content-Type'] = 'application/x-www-form-urlencoded'

    return request
}) 

当然,自定义登录态也会存在过期的情况,我们可以在响应拦截器中捕获出错进行处理:当检测到401token过期代码时,需要把请求队列后面的请求都锁死,防止多次出现401自定义登录态过期的情况,然后发起登录,登陆成功之后再进行解锁行为,触发后续的请求队列执行,并且重新执行本次由于token过期被服务器拒绝的接口,否则会造成请求失败的情况(由于静默登录是用户无感知的,突然出现身份验证信息过期会使用户感觉到特别地奇怪,因此需要重新执行本次请求操作而不是由用户再次点击或者其他的行为再发起):

// 响应拦截
fly.interceptors.response.use(
    (response) => {
        //只将请求结果的data字段返回
        return response.data
    },
    async (err) => {
        if (err.status === 401) {
            //401之后,把后面的请求都锁死 防止再次401
            fly.lock()
            removeCache('token')
            //去登陆 成功之后再unlock
            const isLoginSuccess = await doLogin()
            if (isLoginSuccess) {
                fly.unlock()
            }
                        //新执行本次由于token过期被服务器拒绝的接口
            return fly.request(err.request)
        }
    }
) 

由于请求有可能是并发的,为了防止登录被多次执行,因此对doLogin函数进行了小小的改造(尽管写得很不优雅,但是能力有限,大佬们赐教了):

export async function doLogin() {
        //如果正在登录中则不执行
    if (isLogin) return false
    isLogin = true
        //修改状态为登录中,反正重复多次登录
    removeCache('token')
    const { code } = await wxp.login()
    const data = await login({ code })
    setCache('token', data.data.token)
    isLogin = false
    return true
} 

4.3 整体流程图

小程序静默登录与维护自定义登录态

5.写在最后

细节的读者即可发现,api请求中并未设置最大请求数量的(微信小程序最大支持五个api同时发起),这点是需要补充进来的。总体写下来作者觉得在实现方式上还有进步的空间,作者能力有限,也是一边学习一边探讨,如果哪里写得有问题,请给我留言指出,感谢!

收藏
评论区

相关推荐

H5游戏开发:FC小蜜蜂 | Aotu.io「凹凸实验室」
H5游戏开发:FC小蜜蜂 by TH(https://github.com/ONESUNDAY) on 20180128 使用 Phaser 游戏引擎开发,主要
一文搞懂什么是HTTP与HTTPS
(https://blog.csdn.net/petterp/article/details/102779257)Http与Https的区别。 在最近的开发中,深感网络相关基础知识薄弱,于是趁周末好好总结一
微信小程序部分api 会触发 onShow onHide
解决部分api触发小程序 onShow onHide 首先要明白 微信小程序的 onShow() onHide()分为页面级的和应用级的,应用级的就是app.js里面的那几个,页面级的就是pages里的 当使用了下列api时,均会触发页面级和应用级的onShow onHide 1. 点击右上角小圆点关闭小程序。 2. 图片预览:wx.preview
这种动态条形图+折线图怎么做?今天我来教你!
(https://imghelloworld.osscnbeijing.aliyuncs.com/be22e30670a413de621bfee7b56e4c4b.png) 大家好,我是小五🐶 前几天我看了一个不到2分钟的视频,动态展示了我国的GDP增长。而且是动态条形图和折线图叠加一起使用,比较少见!然后我立了一个Flag
笔趣阁小说api
笔趣阁api小说api,提供小说相关api接口,目前支持笔趣阁(https://m.bqkan.com/)。ip地址:http://49.234.123.245:8082 笔趣阁(https://m.bqkan.com/) 1. 首页 ip/getHome 2. 小说分类 ip/
微信小程序 - 路由实践
欢迎来到我博客阅读:1\. 前言在微信小程序由一个 App()实例,和众多Page()组成。而在小程序中所有页面的路由全部由框架进行管理,框架以栈的形式维护了所有页面,然后提供了以下 API 来进行路由之间的跳转:1. wx.navigateTo2. wx.redirectTo3. wx.navigateBack4.
小程序 - 保存图片到相册
在做小程序项目的时候,有需求要做一个开票功能,开票之后自然就需要查看发票,在让后台做成图片返回之后,我想了一下,查看发票除了需要看发票图片,提供预览图片可以放大缩小看外,最好应该还要有一个保存图片的功能吧。 刚好微信小程序提供了预览和保存相册两个API,就正好用上。因为预览比较简单,我就只是把保存相册的开发流程写下来,供大家也供自己往后参考了,有什
uni-app - 实现热更新及时提醒用户更新
1.原因分析在小程序更新开发版本之后,用户本地并没有对之前版本的小程序进行删除,那么再进入小程序的时候的版本是不会发生变化的,这是由于发版是异步执行,因此新版本将会覆盖的比较慢,本质是小程序的启动方式分为两种,冷启动与热启动。冷启动:指的是用户首次打开或小程序被微信主动销毁后再次打开的情况,此时小程序需要重新加载启动。 热启动:指用户已经打开过某
Taro 3.1 版本正式发布:面向定制化的小程序开发
自 Taro 3.1 体验版推出后,我们不断地根据社区的反馈意见对 3.1 版本进行打磨。主要改进了开放式架构、引入了 CustomWrapper 组件以解决性能问题、提出了原生小程序渐进式混合使用 Taro 的解决方案。经历了 12 个 beta 版本后,终于迎来了 3.1 正式版🎉一、Highlights
微信小程序 - 生命周期篇
为什么需要掌握小程序的生命周期当你的领导张小三给你说: 这个请求应该在应用启动的时候发起呢 页面跳转的时候就要取消异步任务哦 应用隐藏的时候记得关闭一下定时器哈那时候的你会一脸懵逼和不知所措还无从下手吗综上所述:我们理所当然的要对微信小程序的生命周期做到滚瓜烂熟,只有这样才能让领
小程序静默登录与维护自定义登录态
1.背景在小程序中,openid是一个用户对于一个小程序/公众号的标识,开发者可以通过这个标识识别出用户,就如同你的身份证一样。2.什么是静默登录?在普通的应用中,用户通过表单验证登录建立用户体系,这种常见的登录方式一般是通过登录页面表单进行登录,对用户来说是有感的。 在小程序中,由于是基于微信,可以通过微信官方提供的API能力,使我们能够无感知得获取
破解X眼电影字体动态加密|凹凸玩数据
我们在上一篇文章 中提到了,大众点评只是静态字体加密,这次我们抱着学习的态度以猫眼电影为例讲讲如何破解字体动态加密。没有了解过字体加密的小伙伴可以先看看上一篇,本文与上一篇重复的部分就不细讲了。我们打开猫眼电影票房榜单的首页https://maoyan.com/board/1很明显,猫眼电影的榜单进行了字体加密。 让我们回忆一下破解大众点评的步骤:1、下载
微信小程序体验composition-api(类似vue3)
微信小程序compositionapi用该是什么样子? 使用使用起来应该像是这个样子wxue(options) setup配置应该是包含一个setup选项是一个函数,返回的函数可以this.xxx调用,返回的数据可以this.data.xxx用到,如下import wxue, reactive from 'wxue'wxue( setup(option
JAVA回调机制(CallBack)之小红是怎样买到房子的??
JAVA回调机制CallBack 序言最近学习java,接触到了回调机制(CallBack)。初识时感觉比较混乱,而且在网上搜索到的相关的讲解,要么一言带过,要么说的比较单纯的像是给CallBack做了一个定义。当然了,我在理解了回调之后,再去看网上的各种讲解,确实没什么问题。但是,对于初学的我来说,缺了一个循序渐进的过程。此处,将我对回调机制的个人理解,按
小红书很难爬?最新爬取方法教给你啦~
Python进击者第184篇原创文章前言大家好,我是Kuls。之前写的那篇App抓包软件charles的配置说过,超过30在看,马上更下一篇。所以加班加点给大家写了今天这篇文章。本文将会带着大家完完整整的爬取小红书的全过程 小红书需要做的前提工作就是装配好mitmproxy具体的配置过程,我建议大家参照崔大写的来进行安装https://zhuanlan.z