面试题高频之token无感刷新(vue3+node.js)

无感刷新的基本原理

  1. 使用刷新令牌(refresh token):
    ○ 应用程序在首次登录成功后会获得一个访问令牌(access token)和一个刷新令牌(refresh token)。
    ○ 访问令牌通常有较短的有效期,而刷新令牌的有效期较长。
  2. 自动刷新:
    ○ 当访问令牌即将过期时,应用程序会在后台使用刷新令牌来获取新的访问令牌。
    ○ 这个过程通常是透明的,用户不会察觉到任何变化。

业务场景及双token的处理流程图

  1. 请求登录接口拿到两个token,在响应拦截器中存储在本地

javascript 复制代码
service.interceptors.response.use(
  async function (response) {
    // 对响应数据做点什么
    if (response.data.code === 0) {
      response.data.data.token &&
        localStorage.setItem("token", response.data.data.token);
      response.data.data.refresh_token &&
        localStorage.setItem("refresh_token", response.data.data.refresh_token);
      return response.data.data;
    } 
    return response;
  },
  function (error) {
    // 对响应错误做点什么
    return Promise.reject(error);
  }
);
  1. 提交业务表单时候,请求拦截器中请求头携带上短token


javascript 复制代码
service.interceptors.request.use(
  function (config) {
    // 在发送请求之前做些什么
    // token
    if (config.url !== "/login") {
      config.headers["Authorization"] = `Bearer ${localStorage.getItem(
        "token"
      )}`;
    }
    return config;
  },
  function (error) {
    // 对请求错误做些什么
    return Promise.reject(error);
  }
);
vue 复制代码
const onSubmit =  ()=>{
    postFrom().then(res=>{
        if(res.content){
         ElMessage.success('提交成功')
         dialogVisible.value = false
        }else{
         //token失效,跳转登录页
         router.push('/login')
        }
    })
}
  1. 如果此时短token失效
  2. 通过请求getRefresh()接口获取新的token

在发起请求之前,需要在请求拦截器中设置携带长token

javascript 复制代码
service.interceptors.request.use(
  function (config) {
    if (config.url === "/refresh_token") {
      config.headers["Authorization"] = `Bearer ${localStorage.getItem(
        "refresh_token"
      )}`;
    }
    return config;
  },
);
javascript 复制代码
service.interceptors.response.use(
  async function (response) {
    // 对响应数据做点什么
    if (response.data.code === 0) {
      ......
    } else if (response.data.code === 401) {
        console.log('token过期');
        // 请求刷新token
        const result = await getRefresh();
        console.log(result);
    }
    return response;
  },
);
  1. 获取到新的token之后,设置请求头携带新token,再次发起提交表单
javascript 复制代码
if (result.token) {
          console.log('getRefresh()携带长token去重新获取短token', result);
          //拿到新的token之后,设置或更新请求头中的 Authorization 字段。
          response.config.headers.Authorization = `Bearer ${localStorage.getItem("token")}`;
          // 再次发起提交表单的接口/protected
          return service.request(response.config);
        }

此时已经实现,无感刷新token

  1. 假设长token也失效了,则跳转登录页重新获取 长短新token
javascript 复制代码
let isRefreshing = false; //标记是否正在刷新token
// 添加响应拦截器
service.interceptors.response.use(
  async function (response) {
    // 对响应数据做点什么
    if (response.data.code === 0) {
      response.data.data.token &&
        localStorage.setItem("token", response.data.data.token);
      response.data.data.refresh_token &&
        localStorage.setItem("refresh_token", response.data.data.refresh_token);
      return response.data.data;
    } else if (response.data.code === 401) {
      if (!response.config._retry && !isRefreshing ) {
        console.log('token过期');
        isRefreshing = true;  // 标记为正在刷新token
        response.config._retry = true;
        // 请求刷新token
        const result = await getRefresh();
        console.log(result);
        //之所以不需要再次设置新的短token,是因为getRefresh()接口的状态码是0,所以在上面已经设置过新token
        if (result.token) {
          console.log('getRefresh()携带长token去重新获取短token', result);
          //拿到新的token之后,设置或更新请求头中的 Authorization 字段。
          response.config.headers.Authorization = `Bearer ${localStorage.getItem("token")}`;
          isRefreshing = false;
          // 再次发起提交表单的接口/protected
          return service.request(response.config);
        }
      } else if (isRefreshing) { // 已经在刷新,不再重复刷新
        console.log('长token也过期了,跳转登录页');
        isRefreshing = false;
        ElMessage.error('请重新登录');
      }
    }
    return response;
  },
  function (error) {
    // 对响应错误做点什么
    return Promise.reject(error);
  }
);

完整代码

青稞儿/双token无感刷新

相关推荐
fruge4 小时前
Vue项目中的Electron桌面应用开发实践指南
前端·vue.js·electron
York·Zhang8 小时前
VSCode 插件开发完整指南:从零到发布
ide·vscode·node.js·编辑器
这是个栗子10 小时前
【问题解决】用pnpm创建的 Vue3项目找不到 .eslintrc.js文件 及 后续的eslint配置的解决办法
javascript·vue.js·pnpm·eslint
花姐夫Jun11 小时前
基于Vue+Python+Orange Pi Zero3的完整视频监控方案
vue.js·python·音视频
533_12 小时前
[vue3] h函数,阻止事件冒泡
javascript·vue.js·elementui
蒲公英源码12 小时前
php+vue知识付费系统前后端全套源码
vue.js·php
通往曙光的路上12 小时前
day22_用户授权 头像上传
javascript·vue.js·ecmascript
小阳生煎12 小时前
Vue实现全局设置一个刷新按钮 只刷新当面路由页面 不跳转操作功能
vue.js·vue
小光学长12 小时前
基于Vue的儿童手工创意店管理系统as8celp7(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
前端·数据库·vue.js
meichaoWen12 小时前
【Vue】Vue框架的基础知识强化
前端·javascript·vue.js