令牌过期以后刷新token并重调接口

15 篇文章 0 订阅

一、目标

设置客户端时间,只要超过客户端时间,系统自动退回到登录页面;当未超过客户端设置的时间时,调用接口,发现令牌过期了,先调用更新令牌接口,然后再重新调用接口。

我原来的token刷新方式是:登录获取过期时间,在每次调用接口的时候比较当前时间和过期时间,如果调用接口的时候发现即将过期,刷新令牌获取新的时间;如果调用接口发现过期了,退出页面。由于是有相似之处的,所以我在此基础上进行修改。

二、思路

1、在外置参数中设置客户端时间

2、登录的时候存储客户端时间,每次调用接口的时候判断有没有过期

3、登录的时候获取token令牌

4、每次调用接口,后端会进行判断,如果过期,会报401,并在response headers中携带token-expired参数

5、如果获取到这个参数,则进行令牌刷新,并在刷新以后再重新调用过期接口

三、实现

1、在config.js 中设置客户端时间,此处设置7天过期

window.g = {
  EXPIRE_TIME: 7,//过期时间 7天
}

2、在登录的时候存客户端过期时间

//登录的时候设置客户端过期时间
let expires = Date.parse(new Date())/1000 + window.g.EXPIRE_TIME *24*3600 //换算成秒
setExpires(expires)

3、每次调用接口的时候对客户端时间的判断

以get为例:

  async get(url, data, query) {
    //get请求方式
    await expiresCalculation()
      .then(() => {
        //console.log("时间戳没过期");
      })
      .catch(() => {
        //console.log("更新令牌~");
      });
    const options = getOptions(url, "get", data, query);
    return axios(options)
      .then(response => {
        return checkStatus(response);
      })
      .catch(res => {
        return checkCode(res);
      });
  },
import router from '@/router'
import store from '@/store'
import { getExpires } from '@/utils/auth'
const expiresCalculation = () => {
  const expires = getExpires() || 0;
  const nDate = new Date();
  const nTime = nDate.getTime();
  const nTimeSecond = Math.floor(nTime / 1000);
  const expTime = expires - nTimeSecond;

  return new Promise(async (resolve, reject) => {
    //客户端时间过期(7天)就退出界面
    if (expTime && expTime > 0) {
      resolve()
    } else {
      await store.dispatch('user/logout')
      router.push('/login');
    }
  })
}

export default expiresCalculation;

4、调用接口,如果报401,并在response headers中携带token-expired参数,调用令牌刷新接口,获取新token存储,并重新调接口

import {handleRefreshToken} from "@/api/http.js"

fetchData() {
     getExpertPages().then(async res => {
        if (!res) return
        if(res && res.code === 10000){
          this.patList = res.content.list
          this.totalCount = res.content.totalCount
        }else if(res.headers['token-expired']){  //token过期
          let resBack = await handleRefreshToken(res) //刷新token并重新调用
          this.patList = resBack.content.list
          this.totalCount = resBack.content.totalCount
        }
      }).catch(() => {
        ...
      })
}

以get为例:

http.js:

async get(url, data, query) {
    //get请求方式
    await expiresCalculation()
      .then(() => {
        //console.log("时间戳没过期");
      })
      .catch(() => {
        //console.log("更新令牌~");
      });
    const options = getOptions(url, "get", data, query);
    return axios(options)
      .then(response => {
        return checkStatus(response);
      })
      .catch(res => {
        return checkCode(res);
      });
  },
  function checkStatus(response) {
 //处理响应数据
  if (response && response.status === 200) {
    ...
  }else if(response.status === 401){
    return response;
  } else{
    ...
  }
export function handleRefreshToken(response){
  //如果能走到这一步,说明客户端时间已经判断过,再判断下token
  if(response.headers['token-expired']){
    let data = {
      accessToken: getToken(), //访问令牌
      refreshToken: getRefreshToken()//刷新令牌
    }
    return new Promise((resolve, reject) => {
      refreshToken(data).then(async (res) => {
        if (res) {
          const cont = res.content;
          await store.dispatch('user/setNewTokenInfo', cont)
          //重新调用接口
         resolve(await repeatRequest(response))
        }else{
          console.log('token刷新失败')
          reject()
        }
      }).catch(error =>{
        reject(error)
      })
    })
   } else {
     console.log('客户端时间未过期,token过期且无token-expired')
     return false
   }
} 
function repeatRequest(response){
  let dataUrl = `${response.config.baseURL}${response.config.url}`;
  // 二进制流转换为base64
  return axios[response.config.method](dataUrl, {
    params: response.config.params,
  }).then(res => {
    return checkStatus(res)
  }).catch(ex => {
     console.error(ex)
  });
}

四、测试

以上就算实现的代码思路了。

那要怎么测试呢?登录获取正常的令牌,然后用过期的令牌调用接口,然后刷新令牌以后,需要用新的令牌再调用一次接口。所以,我这边考虑在本地storage中加一个changToken的参数做判断,登录以后changToken存入true。如果需要测试,delete这个changeToken参数。删除以后,调用任意接口都会使用一个过期的令牌。刷新令牌重新调用接口以后,参数重新变成true。

即:删除changeToken参数 =〉调用过期token =〉 调用过期token,changeToken参数变true =〉 changeToken参数变true,调用新token。

加入代码:

登录的时候:

window.localStorage.setItem('changeToken', true)

重新调用接口的时候:

function repeatRequest(response){
  window.localStorage.setItem('changeToken', true)
}

请求拦截的时候:

axios.interceptors.request.use(
  config => {
    // 请求拦截
    const isToken = (config.headers || {}).isToken === false;
    let token = store.getters.token
      ? store.getters.token
      : getToken()
        ? getToken()
        : "";
    if (token && !isToken) {
        //用changeToken判断token调用
      if(window.localStorage.getItem('changeToken')) {
        config.headers["Authorization"] = "Bearer " + token 
      }
      else 
      config.headers["Authorization"] = '此处是过期token' 
      config.headers["sysappid"] = sysAppId;
    }
    return config;
  },
  error => {
    return Promise.reject(error);
  }
);

最终实现效果:

 

 

 

 

 

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值