当前位置: 首页 > news >正文

关于公司小程序项目在登录流程获取token并全局使用的梳理(学习篇)

首先打开公司的项目,由于公司前端使用的是tarojs+vue+babel,因此需要先安装tarojs-cli并运行编译

之后研究前端前辈们的代码,来学习一下前端怎么获取token并全局使用

首先思路搞清楚,token是通过调取后端的登录接口,并在后端成功返回后拿到并全局使用的,基于这个思路,我们先看看调用login函数和定义login函数的地方

调用login函数位于src\pages\common\login\index.vue的:

// 调用 useService('Auth')获取一个与认证相关的服务对象,然后调用其 login 方法进行登录操作,
// 传入包含 code、encryptedData 和 iv 的对象作为登录参数,并等待这个异步操作完成
if (await useService('Auth').login({code: wxCode.value,encryptedData: detail.encryptedData,iv: detail.iv
})) {// 如果登录成功且 eventId.value 有值,则触发名为 eventId.value(登录成功) 的事件eventId.value && eventCenter.trigger(eventId.value);// 如果登录成功且 eventId.value 没有值,则执行返回上一页的操作!eventId.value && useNavigateBack();
} else {// 如果登录失败,执行返回上一页的操作useNavigateBack();
}

这里用到了useService('Auth'),而useService函数位于src\service\useService.ts的:

export default function useService(serviceName: string) {//获取了被加载文件的默认导出(假设 serviceName 指向的文件中有一个默认导出的类)。const ctor = require('./' + serviceName).default//返回了一个新的实例化对象,这样调用方就可以使用这个对象上的方法,比如 .login 方法。return new ctor()
}/**
useService('Auth'):当传入 'Auth' 作为参数时,
useService函数会尝试加载 ./Auth,也就是相对路径下名为 Auth.ts 的文件。
由于有 src/service/Auth.ts 文件存在,
并且假设这个文件在当前上下文的相对路径符合 useService 的加载规则,
那么这个调用就会加载 src/service/Auth.ts 文件。
**/

由此可知useService('Auth').login是通过useService函数导出了Auth类对象,并调用其login函数。

我们找到位于src\service\Auth.ts的login函数:

async login(args: AuthPhoneNumberProps) {// 移除名为 "USER_LOGOUT" 的存储项this.useStorage.removeStorage("USER_LOGOUT");// 创建一个加载提示,显示标题为"正在登录...",并在变量 hideLoading 中保存用于关闭提示的函数const hideLoading = useLoading({ title: '正在登录...' });// 调用 this.model.login 方法进行登录操作,将传入的参数 args 展开传递,并解构赋值结果为 [error, response]const [error, { data }] = await this.model.login({...args });// 如果有错误发生if (error) {// 触发名为 "refreshWxCode" 的事件eventCenter.trigger('refreshWxCode');// 关闭加载提示hideLoading();// 直接返回,不继续执行后续代码return;}// 将登录成功后获取的数据提交到 store 的 login mutation 中store.commit('login', data);// 调用名为 "Classes" 的服务获取活跃班级信息await useService('Classes').fetchActiveClassInfo();// 关闭加载提示hideLoading();// 返回 true,表示登录成功并执行了后续操作return true;
}

发现该函数调用store.commit('login', data),这里的data是从后端获取的登录响应数据。

当store.commit('login', data)被调用时,实际上会执行login mutation 函数。

而这个login mutation 函数则是在src\store\index.ts中mutations里定义的:

// 定义 Vuex 的 mutations 对象,用于更改状态
mutations: {// init 方法,用于初始化状态init(state) {// 从本地存储中获取用户信息并设置到 Vuex 的 state 中的 user 属性state.user = useStorage().getStorage(STORE_USER);// 从本地存储中获取 token 并设置到 Vuex 的 state 中的 token 属性state.token = useStorage().getStorage(STORE_TOKEN);},// login 方法,用于处理登录成功后的状态更新login(state, obj) {// 设置登录状态为 truestate.isLoginState = true;// 将登录后的 accessToken 存储到本地存储中,并以 STORE_TOKEN 为键useStorage().setStorage(STORE_TOKEN, obj.accessToken);// 将登录后的用户信息存储到本地存储中,并以 STORE_USER 为键useStorage().setStorage(STORE_USER, obj.user);// 计算并设置登录过期时间到本地存储中,以 STORE_EXPIRATION 为键useStorage().setStorage(STORE_EXPIRATION, new Date().getTime() + (LOGIN_TIME || 720) * 60 * 1000);// 更新 Vuex 的 state 中的 user 属性为登录后的用户信息对象的扩展形式state.user = {...obj.user };// 更新 Vuex 的 state 中的 token 属性为登录后的 accessTokenstate.token = obj.accessToken;},
};

在这里可以看到,state.token在init mutation被赋值一次,在login mutation 函数中被obj.accessToken赋值一次。

之后来到src\request\http.ts,查看配置 HTTP 请求拦截器,因为在发送请求之前,拦截器会对请求进行一些预处理操作(比如说把token传入请求头)

http.interceptors.request = (request) => {// 如果 store 的 getters 中有 tokenif (store.getters.token) {// 将环境变量 TOKEN_NAME 作为键名,把 store 中的 token 值设置到请求头中request.header[process.env.TOKEN_NAME as string] = store.getters.token;}// 设置请求头的 Content-Type 为 application/jsonrequest.header['content-type'] = 'application/json';// 返回修改后的请求配置对象return request;
};

这里用到了store.getters.token,但是赋值的时候明明是赋值给state.token,这两者之间有什么关系呢?

这里查到了他们的关系,state是原始状态数据的存储,而store.getters是基于state计算得到的派生状态,它们共同构成了 Vuex 状态管理中的重要组成部分,为应用的组件提供了可预测、可维护的数据访问方式。而如果没有明确为token定义一个 getter,那么store.getters.token不会自动等同于state.token。所以基于这个角度考虑,我们需要去查token是怎么定义 getter的

回到src\store\index.ts中,发现token的 getter定义代码

getters: {token: (state) => {// 从本地存储中获取存储的过期时间,并转换为浮点数const expirationTime = parseFloat(useStorage().getStorage(STORE_EXPIRATION));// 如果过期时间存在且当前时间小于过期时间if (expirationTime && new Date().getTime() < expirationTime) {// 返回 state 中的 tokenreturn state.token;}// 如果不满足上述条件,返回空字符串return "";},
},

这样就可以在 HTTP 请求拦截器中使用store.getters.token,从而实现每次请求,都来实时判断token是否过期,获取token来全局控制用户登录情况了

相关文章:

  • 【从零开始实现stm32无刷电机FOC】【实践】【7.1/7 硬件设计】
  • 25 基于51单片机的温度电流电压检测系统(压力、电压、温度、电流、LCD1602)
  • MongoDB入门
  • 第十三届蓝桥杯真题Python c组D.数位排序(持续更新)
  • A Learning-Based Approach to Static Program Slicing —— 论文笔记
  • web应用合规(一)双因子认证2FA解决方案
  • 音视频通话 SDK
  • 数据结构——队列的基本操作
  • [leetcode] 70. 爬楼梯
  • 前端工程化之vite
  • 汽修行业的知识库搭建:赋能在线教育与知识付费
  • uni-app之旅-day02-分类页面
  • 端模一体,猎豹移动对大模型机器人发展路径清晰
  • Ubuntu下安装向日葵:闪退
  • 解析.NET框架与平台:构建高效应用程序的基石
  • @angular/forms 源码解析之双向绑定
  • 「前端」从UglifyJSPlugin强制开启css压缩探究webpack插件运行机制
  • 30天自制操作系统-2
  • Android 控件背景颜色处理
  • Apache Spark Streaming 使用实例
  • Apache的80端口被占用以及访问时报错403
  • Centos6.8 使用rpm安装mysql5.7
  • CSS魔法堂:Absolute Positioning就这个样
  • docker容器内的网络抓包
  • extjs4学习之配置
  • golang 发送GET和POST示例
  • Linux编程学习笔记 | Linux多线程学习[2] - 线程的同步
  • mysql 5.6 原生Online DDL解析
  • niucms就是以城市为分割单位,在上面 小区/乡村/同城论坛+58+团购
  • node学习系列之简单文件上传
  • PAT A1120
  • React16时代,该用什么姿势写 React ?
  • SegmentFault 技术周刊 Vol.27 - Git 学习宝典:程序员走江湖必备
  • SwizzleMethod 黑魔法
  • Vue.js源码(2):初探List Rendering
  • Wamp集成环境 添加PHP的新版本
  • 栈实现走出迷宫(C++)
  • 中文输入法与React文本输入框的问题与解决方案
  • ​​​​​​​Installing ROS on the Raspberry Pi
  • ​LeetCode解法汇总518. 零钱兑换 II
  • ​Redis 实现计数器和限速器的
  • #565. 查找之大编号
  • (Redis使用系列) Springboot 使用redis的List数据结构实现简单的排队功能场景 九
  • (八)光盘的挂载与解挂、挂载CentOS镜像、rpm安装软件详细学习笔记
  • (多级缓存)多级缓存
  • (附源码)ssm航空客运订票系统 毕业设计 141612
  • (一)Kafka 安全之使用 SASL 进行身份验证 —— JAAS 配置、SASL 配置
  • (转)机器学习的数学基础(1)--Dirichlet分布
  • .\OBJ\test1.axf: Error: L6230W: Ignoring --entry command. Cannot find argumen 'Reset_Handler'
  • .equal()和==的区别 怎样判断字符串为空问题: Illegal invoke-super to void nio.file.AccessDeniedException
  • .mp4格式的视频为何不能通过video标签在chrome浏览器中播放?
  • .NET CF命令行调试器MDbg入门(三) 进程控制
  • .NET Core Web APi类库如何内嵌运行?
  • .NET IoC 容器(三)Autofac
  • .NET 指南:抽象化实现的基类