面试题高频之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无感刷新

相关推荐
麦麦大数据14 分钟前
neo4j+django+deepseek知识图谱学习系统对接前后端分离前端vue
vue.js·django·知识图谱·neo4j·deepseek·在线学习系统
三翼鸟数字化技术团队2 小时前
Vue自定义指令最佳实践教程
前端·vue.js
Misnearch2 小时前
node.js版本管理
node.js
转转技术团队2 小时前
代码变更暗藏危机?代码影响范围分析为你保驾护航
前端·javascript·node.js
Spark2382 小时前
关于vue3整合tiptap的slash菜单的ts支持
vue.js
Mintopia2 小时前
Node.js高级实战:自定义流与Pipeline的高效数据处理 ——从字母生成器到文件管道的深度解析
前端·javascript·node.js
随笔记2 小时前
Flex布局下,label标签设置宽度依旧对不齐,完美解决(flex-shrink属性)
javascript·css·vue.js
樊小肆3 小时前
实战!从 0 到 1 搭建 H5 AI 对话页面
前端·vue.js
JiangJiang3 小时前
揭秘Vue3源码之computed:懒计算与缓存机制全解析
前端·vue.js·面试
清灵xmf3 小时前
Vue 3 自定义权限指令 v-action
前端·javascript·vue.js·自定义指令