1. 静默登录实现(PC 端)

原因:BI 报表大屏展示的过程中,用户登录态过期,导致需要重新扫码登录,用户体验极差。

1.1. 思路

新增 refresh_token 比原来的 access_token 的有效期长,当 access_token 过期的时候,可以拿有效期更长的 refresh_token,重新自动登录。

1.2. 难点

  • 初步流程:页面发送请求 -> 登录态过期 -> refresh_token 重新登录 -> 更新 access_token -> 刷新页面 location.reload()

1.2.1. 如何做到用户无感知静默登录?

  • 不调用 location.reload(),不刷新页面

  • 优化流程:页面发送请求 -> 登录态过期 -> Promise 缓存请求 -> refresh_token 重新登录 -> 更新 access_token -> 重新发送请求

1.3. Promise 缓存请求核心代码

// 处理时机:axios 拦截器
let retryTasks = [];
const responseErrorInterceptor = (ctx: typeof ajax) => (err) => {
  const { response } = err;
  if (response) {
    const { status } = response;
    switch (status) {
      case 401: // 用户没有登录态
        // !!! 利用 Promise 缓存请求
        new Promise(resolve  => retryTasks.push(() => resolve(axios(response.config))))
        return ajax.$rest.global.getRefreshToken().then(res => {
          if (res.code === 4001) {
            // refresh_token 也过期,跳转登录页,此函数内容省略
            openNoneLogin(ctx);
          }
          if (res.code === 0) {
            cache.setLocalStorageData('access_token', res.data.access_token);
            cache.setLocalStorageData('refresh_token', res.data.refresh_token);
            // 静默登录后重新发起请求,调用 Promise 的 resolve
            retryTasks.forEach(fn => fn())
            // location.reload()
            retryTasks = []
          }
        });
        break;
      default:
        ctx.showTips(`error:${err.response.status}`);
        break;
    }
    const res = normalizeRes(err.response);
    // return Promise.reject(res.data); // 返回接口返回的错误信息
    return res;
  }
  return null;
};

1.4. 需要注意的细节点

  • refresh_token 接口的参数不要使用 query 传递,不安全,直接放 headers 里面。

  • 手动登出的时候,需要清空本地 localStorage 里面的 refresh_token,避免无法切换登录用户。

  • 首次扫码登录成功,将 refresh_token 存储到 localStorage 后,需要删除 url 上面的 refresh_token,避免暴露关键信息。

Copyright © tomgou 2022 all right reserved,powered by Gitbook该文章修订时间: 2023-08-28 17:33:23

results matching ""

    No results matching ""