token:
token的意思是“令牌”,是用户身份的验证方式,最简单的token组成:uid(用户唯一的身份标识)、time(当前时间的时间戳)、sign(签名,由token的前几位+盐以哈希算法压缩成一定长的十六进制字符串,可以防止恶意第三方拼接token请求服务器)。还可以把不变的参数也放进token,避免多次查库。token在服务器端并不保存,当服务器端收到token时,使用服务器端的特定的算法和只有服务器端知道的密钥,计算签名,如果相同则通过验证。token解决了上述的session和cookie的不足,减少了服务器端的开销,不用在服务器端存储会话标志,可以很好的支持分布式和支持多端登录。
关于token的有效期:
token即是获取受保护资源的凭证,当然必须有过期时间。否则一次登录便可永久使用,认证功能就失去了其意义。非但必须有个过期时间,而且过期时间还不能太长。参考各个主流网站的token过期时间,一般不超过1h。
token过期怎么办?
假设后台给的token的有效时间是1个小时,一般后台会给前台返三个参数:token,过期时间,刷新token的时间点。(刷新token的时间点一般比过期时间早20分钟,看后台返回的数据而定)将他们都存进本地localstorage中。每次发起axios请求时,都获取一个当前的时间戳 timestamp。
let timestamp = Math.round(new Date().getTime());
获取timestamp后,把timestamp与先与刷新token的时间点进行比较。若timestamp小于刷新token的时间点,此时不需要刷新。若timestamp大于刷新token的时间点,再将timestamp与过期时间进行对比。若timestamp大于过期时间,token过期,清空localstorage,跳转到登陆进行重新登陆。若timestamp小于过期时间,此时进行token刷新操作。请求后台接口,获取新的token,覆盖原来的本地存储的信息。
完整代码如下,视情况进行修改
axiosInstance.interceptors.request.use((config) => {
// config.headers['Accept'] = 'Content-Type:multipart/form-data'
let data = Vue.prototype.encrypt(JSON.stringify(config.data));
let res={'data':data}
if(config.method=='post'){
// config.data = qs.stringify(res);
var token = localStorage.getItem("token")
if(token) {
config.headers.Authorization = localStorage.token;
//当前时间戳,秒
let timestamp = Math.round(new Date().getTime());
//过了这个时间后需要刷新
let expires = Number(localStorage.getItem("expires"))
//token存在的有效时间
let refresh_expires_in = Number(localStorage.getItem("refresh_expires_in"))
//判断是否需要更换token
if(expires<timestamp){
//判断token是否过期
if(timestamp<refresh_expires_in){
//刷新token-----
console.log('刷新token')
let token2 = localStorage.getItem("token")
localStorage.removeItem("token");
//请求新的接口
let data = {
token: token2
}
// return
reftoken(data).then(res =>{
if(res.data[0]){
let token3 = Data.data[0];
let expires2 = Data.data[1];
let refresh_expires_in2 = Data.data[2];
localStorage.setItem('token',token3)
localStorage.setItem('expires',expires2)
localStorage.setItem('refresh_expires_in',refresh_expires_in2)
config.headers.Authorization = localStorage.token;
config.data = qs.stringify(res);
return config
}
}).catch(err =>{
router.replace({
path: '/Login'
})
console.log('token刷新catch err')
config.data = qs.stringify(res);
return config
})
}else{
console.log('token过期跳转登陆')
router.replace({
path: '/Login'
})
config.data = qs.stringify(res);
return config;
}
}else{
//不需要更换token
config.data = qs.stringify(res);
config.headers.Authorization = localStorage.token;
return config;
}
}else{
//如果没有token
if (!config.showLoading) {
showFullScreenLoading()
}
config.data = qs.stringify(res);
return config;
}
} else if(config.method=='get'){
config.params = res
if (localStorage.token) {
config.headers.Authorization = localStorage.token;
}
return config;
}
// 判断是否存在token,如果存在的话,则每个http header都加上token
if (localStorage.token) {
config.headers.Authorization = localStorage.token;
}
return config;
}, (error) => {
return Promise.reject(error)
})