为了保证系统安全性,用户一段时间不操作应该自动退出。在开发实现上,使用 token 过期来描述,请求到达网关时,若 token 已过期,则后端返回 401,前端自动清除 token。
之前版本为登录后2小时 token 自动过期,略有不妥,现在修改为用户2小时未操作 token 过期,若期间用户有操作,token 自动刷新。
之前实现
config/axios/service.ts中通过后端返回参数判断,若收到401则自动清除 token,reload 本页面,这时触发permission.ts中的路由守卫,判断无 token 状态后跳转 UMS 进行系统登录。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
   |  service.interceptors.response.use(   (response: AxiosResponse<any>) => {     const { config, status, data } = response     if (config.responseType === 'blob') {              console.log('this is blob')       return response     } else if (status === result_code) {       return data     } else {       ElMessage.error(data.message)     }   },   (error: AxiosError) => {     console.log('error=', error)     if (error && String(error).indexOf('401') > -1) {              removeToken()       window.location.reload()     } else if (error && String(error).indexOf('403') > -1) {       ElMessage.error('当前没有操作权限,请联系管理员。')     } else if (error && String(error).indexOf('405') > -1) {              removeToken()       window.location.reload()     } else {       ElMessage.error(error.message)       return Promise.reject(error)     }   } )
 
  | 
 
方法一:使用刷新 refresh token
登录成功后,后端会返回两个 token,一个是 access_token,一个是 refresh_token,分别保存在 cookie 中,后者的过期时间更长。若请求中 access_token 过期,则前端进行 refresh token 操作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
   | const refreshToken = () => {   const refreshToken = userStore.getToken('refresh_token')   refreshToken({     params: refreshToken   })   .then(data => {     if (res.status === 'ok') {       const accessToken = res.data.accessToken       const refreshToken = res.data.refreshToken       await userStore.updateToken(accessToken)       await userStore.updateRefreshToken(refreshToken)     }   })   .catch(error => {     console.error('刷新token失败:', error);   }); }
 
  | 
 
缺点:refresh token操作是在用户请求之后进行的,可能会阻断用户请求,用户需要再次发起请求,没有实现无感刷新。
方法二:前端自动续期
 使用 renewToken 函数定期检查 access_token 的过期时间
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
   | const renewToken() {   const accessToken = userStore.getToken('accessToken');   const expireTime = userStore.getTime('expireTime');      const remainTime = expireTime - Date.now();      if (remainTime < 5 * 60 * 1000) {     renewToken({       params: accessToken     })     .then(data => {       const accessToken = res.data.accessToken       userStore.renewToken('expireTime', data.expireTime);     })     .catch(error => {       console.error('续期Token失败:', error);     });   } }
 
  setInterval(renewToken, 60 * 1000);
 
  | 
 
【注意】
- 需要同时延长 userInfo 和 AccessSyss 的过期时间,因为用户可能 focus 在子系统操作。
cookie.ts 中更新 | import Cookies from "js-cookie"
  export const updateToken = (expireTime: string) => {   const accessToken = Cookie.get(tokenKey)   Cookies.remove(tokenKey)   Cookies.set(tokenKey, token, { expires: expireTime })      const userInfo = Cookie.get(userKey)   Cookies.remove(userKey)   Cookies.set(userKey, JSON.stringify(userInfo), { expires: expireTime })   const sysList = Cookie.get(sysKey)   Cookies.set(sysKey, sysList, { expires: expireTime })   Cookies.remove(sysKey) }
 
  | 
 
javascript