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

相关推荐
冯宝宝^1 小时前
基于mongodb+flask(Python)+vue的实验室器材管理系统
vue.js·python·flask
又写了一天BUG2 小时前
npm install安装缓慢及npm更换源
前端·npm·node.js
cc蒲公英2 小时前
Vue2+vue-office/excel 实现在线加载Excel文件预览
前端·vue.js·excel
森叶2 小时前
Electron-vue asar 局部打包优化处理方案——绕开每次npm run build 超级慢的打包问题
vue.js·electron·npm
小小竹子2 小时前
前端vue-实现富文本组件
前端·vue.js·富文本
danplus3 小时前
node发送邮件:如何实现Node.js发信功能?
服务器·node.js·外贸开发信·邮件群发·蜂邮edm邮件营销·邮件接口·营销邮件
程序员凡尘4 小时前
完美解决 Array 方法 (map/filter/reduce) 不按预期工作 的正确解决方法,亲测有效!!!
前端·javascript·vue.js
Bug缔造者9 小时前
Element-ui el-table 全局表格排序
前端·javascript·vue.js
xnian_10 小时前
解决ruoyi-vue-pro-master框架引入报错,启动报错问题
前端·javascript·vue.js