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

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

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

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

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

javascript 复制代码
// 调用 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的:

javascript 复制代码
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函数:

javascript 复制代码
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里定义的:

javascript 复制代码
// 定义 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) {
    // 设置登录状态为 true
    state.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 属性为登录后的 accessToken
    state.token = obj.accessToken;
  },
};

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

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

javascript 复制代码
http.interceptors.request = (request) => {
  // 如果 store 的 getters 中有 token
  if (store.getters.token) {
    // 将环境变量 TOKEN_NAME 作为键名,把 store 中的 token 值设置到请求头中
    request.header[process.env.TOKEN_NAME as string] = store.getters.token;
  }
  // 设置请求头的 Content-Type 为 application/json
  request.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定义代码

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

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

相关推荐
别催小唐敲代码16 分钟前
嵌入式学习路线
学习
毛小茛2 小时前
计算机系统概论——校验码
学习
babe小鑫2 小时前
大专经济信息管理专业学习数据分析的必要性
学习·数据挖掘·数据分析
吴声子夜歌2 小时前
小程序——布局示例
小程序
winfreedoms3 小时前
ROS2知识大白话
笔记·学习·ros2
在这habit之下3 小时前
Linux Virtual Server(LVS)学习总结
linux·学习·lvs
我想我不够好。3 小时前
2026.2.25监控学习
学习
im_AMBER3 小时前
Leetcode 127 删除有序数组中的重复项 | 删除有序数组中的重复项 II
数据结构·学习·算法·leetcode
CodeJourney_J3 小时前
从“Hello World“ 开始 C++
c语言·c++·学习
luffy54593 小时前
微信小程序页面使用类似filter函数的wxs语法
微信小程序·小程序