vue3笔记(34)refresh token

为了保证系统安全性,用户一段时间不操作应该自动退出。在开发实现上,使用 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
// response 拦截器
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) {
// Unauthorized
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');
// 计算AccessToken的剩余有效时间
const remainTime = expireTime - Date.now();
// 如果AccessToken的剩余有效时间小于5分钟,则发送续期请求
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);

【注意】

  1. 需要同时延长 userInfo 和 AccessSyss 的过期时间,因为用户可能 focus 在子系统操作。
    cookie.ts 中更新
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    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


vue3笔记(34)refresh token
https://guoningyan.com/2023/10/16/vue3笔记(34)refresh-token/
作者
Ningyan Guo
发布于
2023年10月16日
许可协议