axios token权限认证请求机制
参数属性详解
access_token
:axios请求时需要携带的请求头的值refresh_token
:刷新token时需要传的参数expires_in
:token的有效时间,例如66666秒expires
:这个是前端处理expires_in
过后的数据,例如我是在下午3点登陆的,token有效期是3小时,那么经过计算后token的过期时间是下午6点。expires的值就是下午6点(一般都是以时间戳的形式)scope
,token_type
这些参数与本文章的知识逻辑无关,不做变动。
机制流程
1.登陆
用户输入账号,密码进行登陆。登陆成功后,将用户信息和token等信息存到本地localstorage。
2.给全局axios添加请求头
在引入全局axios文件的时候,因为在登陆的时候已经将信息存在localstorage
。所以在引入的时候进行检测,如果有token值那么就将axios全局配置请求头(如果有多个axios对象那么就分别都配置请求头)。
3.给全局请求添加拦截器
在第二步完成之后,全局全部页面中的请求axios都已经配置了请求头,已经能够正常请求获取数据。为了达到token无感刷新的效果,实现逻辑为:
在页面切换中必然会发起若干请求,在每次请求前添加拦截器,判断当前token距离过期时间还剩多久。如果这个时间段处于0-10分钟之间(10分钟仅仅是举例,意思就是在token快要过期的时候提前10分钟把它刷新掉),那么就发起一次请求将token提前刷新一下,避免等过期时接口还存在过期token而发生401错误,从而达到无感刷新token的效果。
所以给axios全局添加请求前的拦截器:
// 获取本地token
const getToken = () => {
let token;
try {
token = JSON.parse(localStorage.getItem("userData"));
} catch (e) {
message.error(e);
return;
}
return token;
};
axios.interceptors.request.use(res => {
beforeAxios()
return res
})
const beforeAxios = () => {
if(token && !tokenIsRefresh) {
const time = token.expires - Date.now()
if (time < 0) {
message.error('登陆信息已失效,请重新登陆!')
localStorage.removeItem('userData')
window.location.href = '/'
} else if(time < validTime && time > 0) {
// console.log('无感刷新')
tokenIsRefresh = true
refresh(token.refresh_token);
}
}
}
4.给全局请求添加处理器
那么既然给axios全局请求前添加了拦截器,那么也需要在axios全局请求后添加处理:如果请求得到的结果为空,或者说因为token问题而认证失败,请求失败,那么将用户退回到登陆页面进行重新登陆:
axios.interceptors.response.use((res) => {
if (res.data.code === 401 || res.code === 401) {
message.error(res.data.message);
localStorage.removeItem('userData')
window.location.href = '/'
} else if (res.data.code === 500) {
message.error(res.data.message);
}
return res;
},
(err) => {
errorHandler(err);
});
const errorHandler = (err) => {
err && process.env.NODE_ENV == "development" && console.error(err);
const newErr = err.toString()
if (newErr.substring(newErr.length - 3) === '401') {
message.error("登陆信息已失效,请重新登陆!",1);
setTimeout(() => {
localStorage.removeItem('userData')
window.location.href = '/'
},1000);
} else if (newErr.substring(newErr.length - 3) === '403') {
message.error('权限不足')
}
else {
// message.error('请重新登录')
// localStorage.removeItem("token");
// setTimeout(() => (window.location.href = "/"), 500);
}
};
至此为止,其实关于axios请求token问题的一整套逻辑已经完成。涉及到token存储,过期处理,无感刷新。
5.另外情况
在实际开发中还可以考虑到一个情况:用户不小心去控制台将localstorage中的全部内容清空,那么系统检测到如果原本存在localstorage中的token有关信息被清除那么就会自动将用户给踢回登陆界面要求用户重新进行登陆。具体实现代码如下:
// 获取本地token
const getToken = () => {
let token;
try {
token = JSON.parse(localStorage.getItem("userData"));
} catch (e) {
message.error(e);
return;
}
return token;
};
window.addEventListener("storage", (e) => {
process.env.NODE_ENV == "development" && console.log(e.key, e.newValue, e.oldValue);
// 如果在控制台中清除userData
if(!getToken()) {
message.error("登陆信息已失效,请重新登陆!",1);
setTimeout(() => {
localStorage.removeItem('userData')
window.location.href = '/'
},1000);
}
});
另外,还可能碰到用户在一个页面登陆然后要去到项目的另一个页面(就比如主界面和后台管理界面)。同理在主界面按照上面步骤进行axios配置即可。全部实现代码就不贴了,因为不同的登陆接口可能具体的字段不一样,但是实现逻辑可以去参考一下。