
双token鉴权校验
面试官:说说cookie、session、token、jwt是什么,单点登录怎么实现前端双token校验单token情况下,前端请求后端接口携带Token校验,但是token失效时间如果设置长了会有安全隐患,设置短了用户需要频繁刷新用户体验不好。解决办法:设置两个Token,也就是登录完接口初...
前端双token校验
单token情况下,前端请求后端接口携带Token校验,但是token失效时间如果设置长了会有安全隐患,设置短了用户需要频繁刷新用户体验不好。
解决办法:
设置两个Token,也就是登录完接口初次返回的,AccessToken和RefreshToken:AccessToken是用于鉴定用户身份,请求每一个接口都需要携带AccessToken;RefreshToken为刷新前者的接口所携带的token,也就是当AccessToken失效时候,调用接口携带RefreshToken返回新的RefreshToken和新的AccessToken,然后自动将新的AccessToken放到接口中重新请求,整个流程为无感操作,提升用户体验。
上述所提到的刷新接口:/auth/refresh,无需经过网关
// token刷新锁
let isRefreshing = false;
// 重试队列
let requests = [],在Access_Token过期后,可能会短时间发送很多个网络请求,这些网络请求拦截器全都会请求刷新Token,这样显然是不合理的。其实只要刷新一次就够了,所以给刷新Token这步操作加一个锁,这也就是为什么要设置isRefreshing的原因。
在请求刷新Token的响应时间内,可能会有多个网络请求到达,我们又暂时没办法处理这些网络请求,所以我们先把这些网络请求promise对象存储到队列requests里面,等到刷新好Token之后再依次处理这些promise对象。
service.interceptors.response.use(
res => {
//accesstoken超时
if (res.data.result_status === 30002) {
//记录当前res
let response = res;
if (!isRefreshing) {
isRefreshing = true;
return tokenRefreshAPI({
token: JSON.parse(window.localStorage.token)
}).then((res) => {
//refreshToken没过期,刷新成功
console.log('tokenRefreshAPI', res.data);
if (res.data.result_status === 0) {
console.log('token刷新成功', res.data);
//重新设置token
window.localStorage.setItem('token', JSON.stringify(res.data.token));
//执行失效的函数
requests.forEach((cb) => cb());
requests = []; // 重新请求完清空
return service(response.config);
} else if (res.data.result_status === 30011) {
console.log('refreshToken过期,请重新登录');
window.localStorage.clear();
router.push('/login');
}
}).finally(() => {
isRefreshing = false;
});
} else {
console.log('token过期,剩余请求存入队列', axiosConfig.url);
// 返回未执行 resolve 的 Promise
return new Promise(resolve => {
// 用函数形式将 resolve 存入,等待刷新后再执行
requests.push(() => {
resolve(service(axiosConfig));
});
});
}
}
return res;
})Token的失效时长设置和前端定时器刷新时长的设置:
- AccessToken:建议设置为20分钟,以确保即使一次刷新失败,用户仍有足够时间进行重试
- RefreshToken:建议设置为30天,以减少用户频繁重新认证的需求,同时保持适当的安全性
- 前端刷新:每9分钟刷新一次访问令牌,以确保访问令牌始终有效

- Clientid是必备的

- reponse
{
"access_token": "B5483047ABCA442FE7C4B5A45F1EBBCB",
"token_type": "bearer",
"refresh_token": "DFBEC5333D5CA349CB9AC88B895FDAC0",
"expires_in": "71999",
"scope": "all",
"member_id": "45",
"user_id": "1914461805866944000",
"group_id": "g001",
"user_name": "DF001605",
"host": null,
"hostIp": null,
"grayHost": null,
"member_name": "jackyun_dev",
"upgradeHost": null,
"isGray": "1",
"pdaUpgradeHost": null,
"jti": "edb4d5f7-6b21-4725-8e13-afe0a57796bb",
"webSocket": null,
"grayWebSocket": null,
"company": "jackyun_dev",
"mobile": "19862171378",
"environment": "dev",
"softVersion": "standard",
"authFlag": null,
"platCode": "JACKYUN",
"clientId": "jackyun_web_browser",
"risk": "0",
"riskToken": null,
"loginDevice": "web_browser",
"fastLoginToken": null,
"isBindWeixinMiniProgram": "0",
"realName": "吴祖涛",
"imgUrl": "",
"jdHost": "",
"networkIp": null,
"isAdmin": null,
"pddHost": "",
"testSwitcher": null,
"softwareCode": null,
"groupUpgradeInfo": null,
"tags": null,
"clientSn": "TC6NROAC-LATW-BROSWER",
"roles": "1",
"apiHost": null,
"spaceHost": null,
"isGreyTestMember": null,
"greyTestWebPath": null,
"forceChangePassword": "0"
}
chatgpt info:

文章评论区
欢迎留言交流