双token无感刷新(vue3+node.js)

无感刷新的基本原理

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

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

  1. 请求登录接口拿到两个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;
    } 
    return response;
  },
  function (error) {
    // 对响应错误做点什么
    return Promise.reject(error);
  }
);
  1. 提交业务表单时候,请求拦截器中请求头携带上短token


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);
  }
);
const onSubmit =  ()=>{
    postFrom().then(res=>{
        if(res.content){
         ElMessage.success('提交成功')
         dialogVisible.value = false
        }else{
         //token失效,跳转登录页
         router.push('/login')
        }
    })
}
  1. 如果此时短token失效
  2. 通过请求getRefresh()接口获取新的token

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

service.interceptors.request.use(
  function (config) {
    if (config.url === "/refresh_token") {
      config.headers["Authorization"] = `Bearer ${localStorage.getItem(
        "refresh_token"
      )}`;
    }
    return config;
  },
);
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,再次发起提交表单
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
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无感刷新

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值