我遇到一个问题,我在任何地方都找不到安全第一且可维护的答案。
想象一下一个仪表板同时执行多个查询,您如何以一种干净,标准的方式处理 refresh_tokens ?
堆栈是(即使此处无所谓):
后端-具有JWT令牌认证的Laravel 前端-带有用于API调用的axios的Vue JS
端点:
JWT刷新工作流程
/* Tablet and up */
@media screen and (min-width: 768px) {
.carousel-inner .active,
.carousel-inner .active+.carousel-item {
display: block;
}
.carousel-inner .carousel-item.active:not(.carousel-item-right):not(.carousel-item-left),
.carousel-inner .carousel-item.active:not(.carousel-item-right):not(.carousel-item-left)+.carousel-item {
-webkit-transition: none;
transition: none;
}
.carousel-inner .carousel-item-next,
.carousel-inner .carousel-item-prev {
position: relative;
-webkit-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
.carousel-inner .active.carousel-item+.carousel-item+.carousel-item+.carousel-item {
position: absolute;
top: 0;
right: -50%;
z-index: -1;
display: block;
visibility: visible;
}
/* left or forward direction */
.active.carousel-item-left+.carousel-item-next.carousel-item-left,
.carousel-item-next.carousel-item-left+.carousel-item {
position: relative;
-webkit-transform: translate3d(-100%, 0, 0);
transform: translate3d(-100%, 0, 0);
visibility: visible;
}
/* farthest right hidden item must be abso position for animations */
.carousel-inner .carousel-item-prev.carousel-item-right {
position: absolute;
top: 0;
left: 0;
z-index: -1;
display: block;
visibility: visible;
}
/* right or prev direction */
.active.carousel-item-right+.carousel-item-prev.carousel-item-right,
.carousel-item-prev.carousel-item-right+.carousel-item {
position: relative;
-webkit-transform: translate3d(100%, 0, 0);
transform: translate3d(100%, 0, 0);
visibility: visible;
display: block;
visibility: visible;
}
}
/* Desktop and up */
@media screen and (min-width: 992px) {
.carousel-inner .active,
.carousel-inner .active+.carousel-item,
.carousel-inner .active+.carousel-item+.carousel-item {
display: block;
}
.carousel-inner .carousel-item.active:not(.carousel-item-right):not(.carousel-item-left),
.carousel-inner .carousel-item.active:not(.carousel-item-right):not(.carousel-item-left)+.carousel-item,
.carousel-inner .carousel-item.active:not(.carousel-item-right):not(.carousel-item-left)+.carousel-item+.carousel-item {
-webkit-transition: none;
transition: none;
}
.carousel-inner .carousel-item-next,
.carousel-inner .carousel-item-prev {
position: relative;
-webkit-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
.carousel-inner .active.carousel-item+.carousel-item+.carousel-item+.carousel-item {
position: absolute;
top: 0;
right: -33.3333%;
z-index: -1;
display: block;
visibility: visible;
}
/* left or forward direction */
.active.carousel-item-left+.carousel-item-next.carousel-item-left,
.carousel-item-next.carousel-item-left+.carousel-item,
.carousel-item-next.carousel-item-left+.carousel-item+.carousel-item,
.carousel-item-next.carousel-item-left+.carousel-item+.carousel-item+.carousel-item {
position: relative;
-webkit-transform: translate3d(-100%, 0, 0);
transform: translate3d(-100%, 0, 0);
visibility: visible;
}
/* farthest right hidden item must be abso position for animations */
.carousel-inner .carousel-item-prev.carousel-item-right {
position: absolute;
top: 0;
left: 0;
z-index: -1;
display: block;
visibility: visible;
}
/* right or prev direction */
.active.carousel-item-right+.carousel-item-prev.carousel-item-right,
.carousel-item-prev.carousel-item-right+.carousel-item,
.carousel-item-prev.carousel-item-right+.carousel-item+.carousel-item,
.carousel-item-prev.carousel-item-right+.carousel-item+.carousel-item+.carousel-item {
position: relative;
-webkit-transform: translate3d(100%, 0, 0);
transform: translate3d(100%, 0, 0);
visibility: visible;
display: block;
visibility: visible;
}
}
进行API调用axios.get('/auth/login').then(res => setTokenAndUser(res))
这是在SPA和SaaS应用程序中非常常见的情况。拥有多个异步API调用并非偶然。
我在这里有什么选择?
我目前的想法是使用以下工作流程使 access_token 持续3天,使 refresh_token 持续一个月:
这使 refresh_token 在网络上的传播减少,并且使并行失败成为不可能,因为我们仅在前端加载时才更改令牌,因此,令牌在失败之前至少可以生存12h。
尽管此解决方案有效,但我正在寻找更安全/标准的方式,有任何线索吗?
答案 0 :(得分:2)
这是我在应用程序中遇到的情况以及解决方法:
我将令牌数据保存在会话存储中,并每次使用刷新令牌API响应进行更新
我在一个页面中有三个get请求,并且我希望这种行为是当令牌到期时 ONLY (仅),其中一个可以调用刷新令牌API,而其他则必须等待响应,当刷新令牌承诺已解决,他们三个都应使用更新的令牌数据重复失败的请求
这是vuex设置:
// here is the state to check if there is a refresh token request proccessing or not
export const state = () => ({
isRefreshing: false,
});
// mutation to update the state
export const mutations = {
SET_IS_REFRESHING(state, isRefreshing) {
state.isRefreshing = isRefreshing;
},
};
// action to call the mutation with a false or true payload
export const actions = {
setIsRefreshing({ commit }, isRefreshing) {
commit('SET_IS_REFRESHING', isRefreshing);
},
};
这是axios设置:
import { url } from '@/utils/generals';
// adding axios instance as a plugin to nuxt app (nothing to concern about!)
export default function ({ $axios, store, redirect }, inject) {
// creating axios instance
const api = $axios.create({
baseURL: url,
});
// setting the authorization header from the data that is saved in session storage with axios request interceptor
api.onRequest((req) => {
if (sessionStorage.getItem('user'))
req.headers.authorization = `bearer ${
JSON.parse(sessionStorage.getItem('user')).accessToken
}`;
});
// using axios response interceptor to handle the 401 error
api.onResponseError((err) => {
// function that redirects the user to the login page if the refresh token request fails
const redirectToLogin = function () {
// some code here
};
if (err.response.status === 401) {
// failed API call config
const config = err.config;
// checks the store state, if there isn't any refresh token proccessing attempts to get new token and retry the failed request
if (!store.state.refreshToken.isRefreshing) {
return new Promise((resolve, reject) => {
// updates the state in store so other failed API with 401 error doesnt get to call the refresh token request
store.dispatch('refreshToken/setIsRefreshing', true);
let refreshToken = JSON.parse(sessionStorage.getItem('user'))
.refreshToken;
// refresh token request
api
.post('token/refreshToken', {
refreshToken,
})
.then((res) => {
if (res.data.success) {
// update the session storage with new token data
sessionStorage.setItem(
'user',
JSON.stringify(res.data.customResult)
);
// retry the failed request
resolve(api(config));
} else {
// rediredt the user to login if refresh token fails
redirectToLogin();
}
})
.catch(() => {
// rediredt the user to login if refresh token fails
redirectToLogin();
})
.finally(() => {
// updates the store state to indicate the there is no current refresh token request and/or the refresh token request is done and there is updated data in session storage
store.dispatch('refreshToken/setIsRefreshing', false);
});
});
} else {
// if there is a current refresh token request, it waits for that to finish and use the updated token data to retry the API call so there will be no Additional refresh token request
return new Promise((resolve, reject) => {
// in a 100ms time interval checks the store state
const intervalId = setInterval(() => {
// if the state indicates that there is no refresh token request anymore, it clears the time interval and retries the failed API call with updated token data
if (!store.state.refreshToken.isRefreshing) {
clearInterval(intervalId);
resolve(api(config));
}
}, 100);
});
}
}
});
// injects the axios instance to nuxt context object (nothing to concern about!)
inject('api', api);
}
这是“网络”标签中显示的情况:
如您所见,这里有三个失败的请求,出现401错误,然后有一个refreshToken请求,之后所有失败的请求都被更新的令牌数据再次调用