如何在 React.js 应用程序中刷新 JWT 令牌?
How to refresh JWT tokens in React.js Application?
我在这里检查了所有类似的问题,但 none 有我需要的。
我在我的应用程序中保护路由,并在每个请求中发送 JWT,这里一切都很好。
问题是当 JWT 过期时,我需要知道如何刷新该令牌并让用户保持登录状态,而不是注销用户。
每个人都在谈论创建一个 "Middleware" 来处理这个问题,但没有人说如何创建该中间件以及其中包含什么?
那么,这样做的最佳做法是什么?我应该在发送任何请求之前检查 JWT 到期日期吗?或者我应该等待“401”响应然后尝试刷新令牌(我不知道该怎么做),或者究竟是什么?
如果有人在 Github 上有这样的中间件或包或项目的工作示例可以帮助我解决这个问题,那就太好了。
我只对流程的前端部分感兴趣,从 React 发送什么,我应该期望收到什么以及如何处理它。
你的中间件应该看起来像这个代码块(例如你可以使用任何你想要的)
/* eslint-disable */
import request from 'superagent';
function call(meta, token) {
const method = meta.API_METHOD ? meta.API_METHOD : 'GET';
let req = request(method, 'http://localhost:8000/' + meta.API_CALL);
req = req.set({ Authorization: `JWT ${token}` });
req = meta.API_TYPE ? req.type('Content-Type', meta.API_TYPE) : req.set('Content-Type', 'application/json');
if (meta.API_PAYLOAD) {
req = req.send(meta.API_PAYLOAD);
}
if (meta.API_QUERY) {
req.query(meta.API_QUERY);
}
return req;
}
export default store => next => action => {
const state = store.getState();
const token = state.logged && state.logged.get('token') ?
state.logged.get('token') : 'eyJhbGciOiJIUzUxMiJ9';
if (action.meta && action.meta.API_CALL) {
call(action.meta, token)
.then((res) => {
store.dispatch({
type: action.meta.API_SUCCESS,
result: res.body,
});
})
.catch(({ status, response }) => {
if (action.meta.API_ERRORS && action.meta.API_ERRORS[status]) {
return store.dispatch({
type: action.meta.API_ERRORS[status],
result: response.body,
});
}
if (action.meta.API_ERRORS && action.meta.API_ERRORS[status] === '401') {
/*call the refresh token api*/
call(<Your Meta for refreshing>, <expiredtoken>)
.then((res) => {
store.dispatch({
type: action.meta.API_SUCCESS,
result: res.body,
});
})
.catch(({ status, response }) => {
if (action.meta.API_ERRORS && action.meta.API_ERRORS[status]) {
return store.dispatch({
type: action.meta.API_ERRORS[status],
result: response.body,
});
}
throw response;
});
}
throw response;
});
}
return next(action);
};
如果您正在使用 Axios(我强烈推荐),您可以在响应的 interceptors 中声明您的令牌刷新行为。这将适用于 Axios 发出的所有 https 请求。
过程是这样的
- 正在检查错误状态是否为 401
-
- 如果有有效的刷新令牌:使用它来获取访问令牌
- 如果没有有效的刷新令牌:注销用户并return
- 使用新令牌重新请求。
这是一个例子:
axios.interceptors.response.use(
(response) => {
return response
},
(error) => {
return new Promise((resolve) => {
const originalRequest = error.config
const refreshToken = localStorage.get('refresh_token')
if (error.response && error.response.status === 401 && error.config && !error.config.__isRetryRequest && refreshToken) {
originalRequest._retry = true
const response = fetch(api.refreshToken, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
refresh: refreshToken,
}),
})
.then((res) => res.json())
.then((res) => {
localStorage.set(res.access, 'token')
return axios(originalRequest)
})
resolve(response)
}
return Promise.reject(error)
})
},
)
我在这里检查了所有类似的问题,但 none 有我需要的。 我在我的应用程序中保护路由,并在每个请求中发送 JWT,这里一切都很好。 问题是当 JWT 过期时,我需要知道如何刷新该令牌并让用户保持登录状态,而不是注销用户。
每个人都在谈论创建一个 "Middleware" 来处理这个问题,但没有人说如何创建该中间件以及其中包含什么?
那么,这样做的最佳做法是什么?我应该在发送任何请求之前检查 JWT 到期日期吗?或者我应该等待“401”响应然后尝试刷新令牌(我不知道该怎么做),或者究竟是什么?
如果有人在 Github 上有这样的中间件或包或项目的工作示例可以帮助我解决这个问题,那就太好了。
我只对流程的前端部分感兴趣,从 React 发送什么,我应该期望收到什么以及如何处理它。
你的中间件应该看起来像这个代码块(例如你可以使用任何你想要的)
/* eslint-disable */
import request from 'superagent';
function call(meta, token) {
const method = meta.API_METHOD ? meta.API_METHOD : 'GET';
let req = request(method, 'http://localhost:8000/' + meta.API_CALL);
req = req.set({ Authorization: `JWT ${token}` });
req = meta.API_TYPE ? req.type('Content-Type', meta.API_TYPE) : req.set('Content-Type', 'application/json');
if (meta.API_PAYLOAD) {
req = req.send(meta.API_PAYLOAD);
}
if (meta.API_QUERY) {
req.query(meta.API_QUERY);
}
return req;
}
export default store => next => action => {
const state = store.getState();
const token = state.logged && state.logged.get('token') ?
state.logged.get('token') : 'eyJhbGciOiJIUzUxMiJ9';
if (action.meta && action.meta.API_CALL) {
call(action.meta, token)
.then((res) => {
store.dispatch({
type: action.meta.API_SUCCESS,
result: res.body,
});
})
.catch(({ status, response }) => {
if (action.meta.API_ERRORS && action.meta.API_ERRORS[status]) {
return store.dispatch({
type: action.meta.API_ERRORS[status],
result: response.body,
});
}
if (action.meta.API_ERRORS && action.meta.API_ERRORS[status] === '401') {
/*call the refresh token api*/
call(<Your Meta for refreshing>, <expiredtoken>)
.then((res) => {
store.dispatch({
type: action.meta.API_SUCCESS,
result: res.body,
});
})
.catch(({ status, response }) => {
if (action.meta.API_ERRORS && action.meta.API_ERRORS[status]) {
return store.dispatch({
type: action.meta.API_ERRORS[status],
result: response.body,
});
}
throw response;
});
}
throw response;
});
}
return next(action);
};
如果您正在使用 Axios(我强烈推荐),您可以在响应的 interceptors 中声明您的令牌刷新行为。这将适用于 Axios 发出的所有 https 请求。
过程是这样的
- 正在检查错误状态是否为 401
-
- 如果有有效的刷新令牌:使用它来获取访问令牌
- 如果没有有效的刷新令牌:注销用户并return
- 使用新令牌重新请求。
这是一个例子:
axios.interceptors.response.use(
(response) => {
return response
},
(error) => {
return new Promise((resolve) => {
const originalRequest = error.config
const refreshToken = localStorage.get('refresh_token')
if (error.response && error.response.status === 401 && error.config && !error.config.__isRetryRequest && refreshToken) {
originalRequest._retry = true
const response = fetch(api.refreshToken, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
refresh: refreshToken,
}),
})
.then((res) => res.json())
.then((res) => {
localStorage.set(res.access, 'token')
return axios(originalRequest)
})
resolve(response)
}
return Promise.reject(error)
})
},
)