微信小程序静默登录和维护自定义登录态详解

目录
  • 1.背景
  • 2.什么是静默登录?
  • 3.如何维护自定义登录态
  • 4.静默登录整体流程
    • 4.1app.onLaunch中发起登录
    • 4.2处理小程序不支持异步阻塞
      • 4.2.1粗糙的方案
      • 4.2.2优雅的方式
    • 4.3 整体流程图
  • 5.写在最后

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同时发起),这点是需要补充进来的。总体写下来作者觉得在实现方式上还有进步的空间,作者能力有限,也是一边学习一边探讨!

到此这篇关于微信小程序静默登录和维护自定义登录态的文章就介绍到这了,更多相关微信小程序静默登录内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 微信小程序静默登录的实现代码

    1.通过 wx.login获取 登录凭证(code) wx.login({ success: function (res) { console.log(res.code): } }) 2.在此处获得 appid 和 secret :https://developers.weixin.qq.com/sandbox 如图 3.小程序端 http://127.0.0.1:8080/jeecg-boot 这一段是自己的访问路径 //app.js App({ globalData: { appid: ''

  • 微信小程序 页面跳转事件绑定的实例详解

    微信小程序 页面跳转事件绑定的实例详解 什么是事件 事件是视图层到逻辑层的通讯方式. 事件可以将用户的行为反馈到逻辑层进行处理. 事件可以绑定在组件上,当达到触发事件,就会执行逻辑层中对应的事件处理函数. 事件对象可以携带额外信息,如 id, dataset, touches. 在组件中绑定一个事件处理函数. 如bindtap,当用户点击该组件的时候会在该页面对应的Page中找到相应的事件处理函数 <view bindtap="view"> <text bindtap

  • 微信小程序中子页面向父页面传值实例详解

    微信小程序中子页面向父页面传值实例详解 上面一张图是编辑款项页面,下面一张图是点击了编辑款项页面中选择好友的图标后打开的子页面.这个时候点选子页面的某个好友时,需要把好友的名字传递回编辑款项父页面. 采取的方法: 从页面路由栈中直接获取和操作目标Page对象,这种方式,是通过调用小程序的API: getCurrentPages(),来获取当前页面路由栈的信息,这个路由栈中按照页面的路由顺序存放着相应的Page对象,我们可以很容易的获取到上一级页面的完整Page对象,从而使直接调用Page对象的属

  • 微信小程序 消息推送php服务器验证实例详解

    微信小程序 消息推送php服务器验证实例详解 微信文档(靠下有个"接入指引"):https://mp.weixin.qq.com/debug/wxadoc/dev/api/custommsg/callback_help.html 设置页面("设置">>"开发设置"): https://mp.weixin.qq.com/wxopen/initprofile?action=home&lang=zh_CN 1.设置服务器域名 比如:

  • 微信小程序 监听手势滑动切换页面实例详解

    微信小程序 监听手势滑动切换页面实例详解 1.对应的xml里写上手势开始.滑动.结束的监听: <view class="touch" bindtouchstart="touchStart" bindtouchmove="touchMove" bindtouchend="touchEnd" ></view> 2.js: var touchDot = 0;//触摸时的原点 var time = 0;// 时

  • 微信小程序本地缓存数据增删改查实例详解

    微信小程序本地缓存数据增删改查实例详解 数据如: var user = { name: 'Lion', sex: 'guy' } CRUD: // 添加 wx.setStorageSync('user', user); // 查询 var developer = (wx.getStorageSync('user') || []); // 更改 developer.name = 'Lion01'; wx.setStorageSync('user', user); // 删除 wx.removeSt

  • 微信小程序request请求后台接口php的实例详解

    微信小程序request请求后台接口php的实例详解 后台php接口:http://www.vueyun.com/good/info 没有处理数据,直接返回了,具体再根据返回格式处理 public function getGoodInfo(Request $request) { $goods_datas = $this->Resource->get(); return response()->json(['status' => 'success','code' => 200,

  • 微信小程序点击控件修改样式实例详解

    微信小程序点击控件修改样式实例详解 现在要在微信小程序中实现点击控件修改样式,如下: 微信小程序中不支持直接操作dom,要实现这种效果,我们需要通过设置data,然后利用数据和界面的双向绑定来实现它. 第一步:在wxss中定义被点击和未被点击的样式,如下: .service_selection .is_checked{ border: 1px solid #FE0002 ; color: #FE0002 ; background: #fff; } .service_selection .norm

  • 微信小程序wx:for和wx:for-item的用法详解

    wx:for="{{list}}"用来循环数组,而list即为数组名wx:for-item="items" 即用来定义一个循环过程中每个元素的变量的 如果是一维数组,按照如下方式循环出来: <view wx:for="{{list}}"> {{index}} {{item.name}} </view> 以上代码中,item即为list的别名. 如果是二维甚至多维数组,按照如下方式循环: <view wx:for=&q

  • 微信小程序中的列表切换功能实例代码详解

    感觉这列表切换有点类似于轮播图,而且感觉这代码直接可以拿来用,稍微改一改样式什么的就OK了,列表切换也是用到的地方也很多 wxml中的代码如下: <!-- 标签页面标题 --> <view class="tab"> <view class="tab-item {{tab==0?'active':''}}" bindtap="changeItem" data-item="0">音乐推荐<

  • SpringBoot+微信小程序实现文件上传与下载功能详解

    目录 1.文件上传 1.1 后端部分 1.2 小程序前端部分 1.3 实现效果 2.文件下载 2.1 后端部分 2.2 小程序前端部分 2.3 实现效果 1.文件上传 1.1 后端部分 1.1.1 引入Apache Commons FIleUpload组件依赖 <!--文件上传与下载相关的依赖--> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fil

随机推荐