关于公司小程序项目在登录流程获取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来全局控制用户登录情况了

相关推荐
chao_6666663 分钟前
【深度】为GPT-5而生的「草莓」模型!从快思考—慢思考到Self-play RL的强化学习框架
人工智能·深度学习·学习·机器学习
丹丹的笑意27 分钟前
学习记录:js算法(四十七):相同的树
javascript·学习·算法
Ace'1 小时前
学习笔记&&每日一题
笔记·学习·算法
开源哥661 小时前
基于Springboot+微信小程序 的高校社团管理小程序(含源码+数据库+lw)
spring boot·微信小程序·小程序
mez_Blog1 小时前
React学习笔记(3.0)
前端·笔记·学习·react.js·前端框架
说私域1 小时前
开源 AI 智能名片 S2B2C 商城小程序与营销工具的快速迭代
人工智能·小程序
啊波阿波波1 小时前
NLP--自然语言处理学习-day1
学习·自然语言处理·easyui
秋秋秋叶2 小时前
【2】图像视频的加载和显示
opencv·学习
斯派的曼2 小时前
学习C++的第七天!
开发语言·c++·学习
苏格拉没有底1112 小时前
数据结构——顺序表、链表
c语言·开发语言·数据结构·笔记·学习·算法·链表