看了很多token自动刷新文章,还是想笼统问下...
最近接到一个新需求,就是登录后进入到大屏,大屏是需要一直挂着展示,不要让它频繁掉线重新登录,方案是让前端实现token定时自动刷新,防止频繁掉线重新登录,但是目前后端返回的只有token值,没有返回过期时间,也没有提供给刷新token的接口,这种情况下前端如何实现自动刷新?需要后端给我提供什么or如何处理?
看了很多token自动刷新文章,还是想笼统问下...
最近接到一个新需求,就是登录后进入到大屏,大屏是需要一直挂着展示,不要让它频繁掉线重新登录,方案是让前端实现token定时自动刷新,防止频繁掉线重新登录,但是目前后端返回的只有token值,没有返回过期时间,也没有提供给刷新token的接口,这种情况下前端如何实现自动刷新?需要后端给我提供什么or如何处理?
没有刷新token的接口,有获取token的接口么。
有的话定时去调用这个接口主动更新token即可。
没有的话是后端把token写入cookie的么,那这个就得和后端联合开发了。
需要后端返回token和refreshToken,当token过期的时候,在响应拦截器中判断,请求刷新token的接口,携带之前的refreshToken,换回新的token和refreshToken并存储到状态管理库或缓存。
需要注意的是,需要记录失败的请求,后续重新获取新的token后,重新发起请求。
要避免多次请求触发响应拦截器对于token过期的处理逻辑,可以加一个状态变量(isRefresh)来控制,防止多次触发导致token一直处于失效的状态。
大屏的数据,应该是定时刷新的吧,不然统计数据改变,还有重新手动刷新一下数据吗,
有定时刷新,就不用担心掉线,刷新的时候更新一下token,或后端有处理,前端不用处理,就不会掉线。
如果需要实现无感刷新,一般会生成两个token。
token:用于用户正常验证。
refresh_token:更新(生成新)token时,需要验证refresh_token是否过期或被篡改。
当验证token时,发现token过期时返回自定义状态码
前端使用响应拦截器,根据自定义的状态码进行拦截。
使用refresh_token来重新生成token然后重发请求
需要后端配合设计一个token 刷新接口
后端实现
const express = require('express')
const jwt = require('jsonwebtoken');
const app = express();
app.get('/login', (req, res) => {
const { name, password } = req
//登陆的时候用登录的账号和密码生成 refresh_token 过期时间 12 小时
const refresh_token = jwt.sign({ name: "name", password: "123456" }, 'token', {
{ expiresIn: "12h" }
})
// 用生成的 refresh_token 去生成 token 返回到前端 过期时间 15 分钟
const token = jwt.sign({ refresh_token: refresh_token }, 'token', {
expiresIn: "15m"
})
res.status(200).send({ refresh_token, token })
})
app.get('/refresh_token', (req, res) => {
const { data } = req
jwt.verify(data.refresh_token, "bad secret", (error, decoded) => {
if (error) {
console.log("refresh_token 也过期了,需要重新登陆")
return
}
// refresh_token 没有过期, 刷新 token返回前端
const token = jwt.sign({ refresh_token: refresh_token }, 'token', {
expiresIn: "15m"
})
res.status(200).send({ token })
})
})
app.listen(3000);
前端实现
import axios from 'axios'
import store from '@/store'
import {
httpUrlbase
} from '@/utils/api.js'
import {
Message
} from 'element-ui'
// 创建axios实例
const service = axios.create({
baseURL: httpUrlbase, // url = base url + request url
timeout: 120000 // 请求超时设置
})
service.defaults.headers = {
'Content-Type': 'application/json;charset=UTF-8'
}
// 请求拦截器
service.interceptors.request.use(
config => {
//给请求头添加token
if (store.getters.token) {
config.headers['Token'] = store.getters.token
}
//给请求参数去除前后空格
if (config.method.toLowerCase() == 'post') {
for (let key in config.data) {
config.data[key] = typeof config.data[key] == 'string' ? config.data[key].trim() : config.data[key]
}
} else {
for (let key in config.params) {
config.params[key] = typeof config.params[key] == 'string' ? config.params[key].trim() : config.params[key]
}
}
return config
},
error => {
// 处理请求错误
return Promise.reject(error)
}
)
// 响应拦截
service.interceptors.response.use(
response => {
//从响应体里面结构出config(请求体)data(响应数据别名为res)
const {
config,
data: res,
} = response
// 如果自定义代码不是'10000',则判断为错误。
if (res.code && res.code + '' !== '10000') {
//code 40007 sub_code以'token-is-expired'结束code为业务状态码sub_code为具体错误状态码
if (res.code + '' == '40007' && (res.sub_code.endsWith('token-is-expired'))) {
return new Promise(function (resolve, reject) {
//post请求放到request body响应的时候是json字符串所以要转为json对象
if (config.method.toLowerCase() == 'post') {
config.data = JSON.parse(config.data)
}
//获取新的token
const verificationResult = await service({
url: "/api/v1/refresh_token",
method: "POST",
data: {
refresh_token:store.getters.refresh_token
}
})
if (verificationResult && verificationResult.code == "10000") {
store.commit("user/SET_TOKEN", verificationResult.data.token)//存储token
const newRes = await service(config) //重发请求
resolve(newRes);//将响应结果返回到业务层
}
})
} else {
Message(res.sub_message);//统一错误提示
}
} else {
return res
}
},
error => {
Message({
message: error.message,
type: 'error',
duration: 5 * 1000
})
return Promise.reject(error)
}
)
export default service
大概就是这么一个流程,在网上总结的一些代码,你做一个参考吧
你们这个token过时刷新页面是怎么个实现方式?在点击新链接后,后台检查token过期,把url拦截了?
token 是前后台通信数据,你肯定需要后台协助的。
后台可以提供一个心跳链接接口,前端定时发送心跳请求,确保前端存活,让后台刷新token过期时间。
又或者如楼上所说,让后台提供获取新token的接口,前端定时获取新token,刷新cookie中的token。
又或者,你在cookie中保存了用户名密码,用异步方式调用后台登录接口,重新登录获取新的token。这个不太好,除非后台实在不想配合,非得你自己完成这个功能...
10 回答11.3k 阅读
5 回答4.9k 阅读✓ 已解决
4 回答3.2k 阅读✓ 已解决
2 回答2.8k 阅读✓ 已解决
3 回答5.2k 阅读✓ 已解决
1 回答3.4k 阅读✓ 已解决
3 回答2.4k 阅读✓ 已解决
最好的方法就是去跪求后端大哥,提供一个RefreshToken机制和接口,并约定一个token的固定有效期(比如两个小时)或者增加字段过期时间/有效期限,然后前端根据需要可以在token快过期的时候用refreshToken请求一个新的token值,后端保证新旧token值都同时有效,旧tokn过期时间过了旧token即刻失效,完全切换到新token。
如果后端不好大改,只有做一个请求进度框了,做不到无感,只能是定时刷新token,请求的时候如果发现token刚好失效,重新获取token,并显示请求进度框,最多就是请求进度状态的组件显示在数据显示区域,可以不弹窗那样突兀。
RefreshToken 可以多自己搜索理解下,知乎,掘金都可以去搜搜看。