我们为什么要无感刷新呢?
我们都知道,后台返回的token是有时效性的,时间到了,你在交互后台的时候,后台会判断你的token是否过期(安全需要),如果过期了就会通过邪恶的手段逼迫你重新登陆!
【每天几个面试题|token过期?页面如何实现无感刷新?】
无感刷新是什么?
前面说到缩短token时间就会加大我们网站的安全性,但是缩短token用户就会生气了,所以为了让用户不生气,我们使用双token刷新、续期。
双token是啥?access_token(短token—请求时带给后台的)和refresh_token(长token—用于刷新)
活跃用户是啥? 我们这里判定access_token创建开始到2*access_token的时间为活跃(只要在这个时间段内,监听用户有操作就是活跃).
使用双token
用户第一次用账号密码登录,服务器返回3个参数: access_token、refresh_token和expires_in(短token过期时间,这里返回7200),时效长短不一样。短的access_token 时效过了之后,发送时效长的 refresh_token 重新获取一个短时效token,如果都过期,就需要重新登录了。
refresh_token 就是用来刷新access_token 。
活跃用户的access_token 过期了,用refresh_token获取新的access_token。
步骤如下:
1-token过期根据refresh_token获取新的token 重新获取数据
2-创建一个新的axios实例 【使用request防止再次进入请求拦截和请求响应而进入死循环】
3-根据请求相应的响应值 是不是401 是:说明token过期
然后进行判断store中的 user :{token:'*****',refresh_token:'******'}中的 refresh_token和user对象是否存在 ,如果不存在说明之前没有登录过,直接去登录
4-使用新创建的axios 实例对象 requestFreshToken 发送新的请求 headers中的口令携带的是 refresh_token
5-获取token之后 将值重新赋值给user中的token
6-将user重新存入store中
7-重新获取刚才因为token失效而没有获取的数据 直接使用request 参数 来自error对象中【这里保存了之前token失效的请求数据】
代码如下:
// 导入axios, 后期会使用它创建出一个request实例, 用于发送请求
import axios from "axios"// 导入store, 后期会使用它对vuex里面的user信息进行修改操作
import store from "@/store"// 导入router, 后期会使用它进行路由跳转, 如果没有token和token过期直接跳转到login页面
import router from "@/router"// jsonBig是一个包, 主要是对后端返回大数字的问题进行处理
import jsonBig from "json-bigint"// 应该是移动端, 类似于element ui里面的this.$message.success等等
import { Toast } from "vant"// 第一个axios实例是用于发送请求
const request = axios.create({
// axios提供了一个api, transformResponse
// 它可以将后端的原数据进行自定义操作
// 如果后端不进行处理, 那我们就可以使用下包的方式来进行手动的处理
transformResponse: [
function(data) {
try {
// 如果请求发送成功, 就将可能包含大数字的数据转换成一个BigNumber类型的对象, 它可以超出js的安全整数范围
return jsonBig.parse(data)
} catch (err) {
// 如果转换失败,则包装为统一数据格式并返回
return {
data
};
}
}
]
});
// 第二个axios实例用来当token失效的时候, refreshToken发送请求, 获取最新的token, 然后将错误的信息从新发送
// 作用就是防止, 再次使用第一个axios实例发送请求, 请求拦截器死循环
const requestFreshToken = axios.create()// 添加请求拦截器
request.interceptors.request.use(
// 成功的回调
function(config) {
// 如果user对象里面有token, 就说明是登录过的且token在失效期限内
if (store.state.user) {
// Bearer 是一个http身份验证的规则, 发送请求必须加上
config.headers.Authorization = "Bearer " + store.state.user.token
}
return config
},// 错误的回调
function(error) {
return Promise.reject(error)
}
)// 添加响应拦截器
request.interceptors.response.use(
// 响应拦截器的第一个回调函数, 成功走
function(response) {
console.log(response, 3)return response;
},
// 响应拦截器的第二个回到函数, 失败走
async function(error) {
console.log(error.response, 222)
// 获取错误的response中的status状态
const status = error.response.status// 如果浏览器返回的状态是为400, 那么就表示前端参数可能出现问题
if (status == 400) {
// 使用vant中的toast方法抛出一个提示
Toast.file("请求参数错误")
} else if (status == 401) { // 如果后端返回的状态为401, 就表示用户可能没有token, 或者token已经过期// 这里一共会出现三个情况:
// 1. 用户没有登录
// 2. 用户有登录, 发送请求发现token已经过去
// 3. 出现异常// 调用vuex中state中存储的user信息
const { user } = store.state;
// 这里走的是没有登录的情况
// 查看有没有存储refresh_token
if (!user || !user.refresh_token) {// 如果没有就直接调换到login页面
return router.push("/login")
}// 这里走的是token已经失效的情况
// 为什么需要try一下, 因为发送ajax可能会成功, 也可能会失败
try {
// 这里使用的requestFreshToken实例发送请求异步请求, 因为如果在使用request会陷入死循环
const { data } = await requestFreshToken({
method: "PUT",
url: "/v1_0/authorizations",
headers: {
// 直接使用登录时, 存储的refresh_token发送新请求, 获取新的token// 无感刷新也就在于这里
// 当浏览器发送请求, 请求拦截器发现token已经失效
// 那么就需要使用到refresh_token来发送请求, 获取新的token
// 服务器响应之后将新的token存储本地, 最后将失败的请求发送出去
Authorization: "Bearer " + user.refresh_token
}
});
// 将服务器返回的新token重新保存到user里面
user.token = data.data.token// 注意, 想要修改state里面的数据, 必须通过mutations, 因为数据追踪的就知道是谁修改的
store.commit("setUser", user)return request(error.response.config)
} catch (error) {}// 出现异常直接返回登录页
return router.push("/login")
Toast.file("用户认证失败")
} else if (status == 403) {
// 客户端没有权限
Toast.file("客户端没有权限")
} else if (status == 405) {
//请求方法不支持
Toast.file("请求方法不支持")
}// 如果服务器返回的状态码, 以上if判断都不存在, 那么直接抛出错误
return Promise.reject(error)
}
)// 最后导出request实例, 供其他组件发送ajax时使用
export default request
推荐阅读
- web|CSS 3之鼠标特效
- web|CSS 3之美化菜单
- SSM框架基于JavaWeb在线投票系统的设计与实现源码+论文+ppt+代码讲解视频+安装视频(包安装)
- 网络|音视频技术开发周刊 | 224
- 性能优化|Android 项目架构系列之代码的混淆
- jar|Android logfilter抓log
- android|adb 打印activity堆栈
- mysql|SQL优化万能公式(5 大步骤 + 10 个案例)
- web安全|常见Web安全漏洞--------sql注入