fix(projects): fix refresh token when meet multi requests. fixed #581
This commit is contained in:
parent
79b2a28b5a
commit
27b5222cfb
2
.env
2
.env
@ -36,7 +36,7 @@ VITE_SERVICE_LOGOUT_CODES=8888,8889
|
|||||||
VITE_SERVICE_MODAL_LOGOUT_CODES=7777,7778
|
VITE_SERVICE_MODAL_LOGOUT_CODES=7777,7778
|
||||||
|
|
||||||
# token expired codes of backend service, when the code is received, it will refresh the token and resend the request
|
# token expired codes of backend service, when the code is received, it will refresh the token and resend the request
|
||||||
VITE_SERVICE_EXPIRED_TOKEN_CODES=9999,9998
|
VITE_SERVICE_EXPIRED_TOKEN_CODES=9999,9998,3333
|
||||||
|
|
||||||
# when the route mode is static, the defined super role
|
# when the route mode is static, the defined super role
|
||||||
VITE_STATIC_SUPER_ROLE=R_SUPER
|
VITE_STATIC_SUPER_ROLE=R_SUPER
|
||||||
|
@ -4,7 +4,7 @@ import { useAuthStore } from '@/store/modules/auth';
|
|||||||
import { $t } from '@/locales';
|
import { $t } from '@/locales';
|
||||||
import { localStg } from '@/utils/storage';
|
import { localStg } from '@/utils/storage';
|
||||||
import { getServiceBaseURL } from '@/utils/service';
|
import { getServiceBaseURL } from '@/utils/service';
|
||||||
import { handleRefreshToken, showErrorMsg } from './shared';
|
import { getAuthorization, handleExpiredRequest, showErrorMsg } from './shared';
|
||||||
import type { RequestInstanceState } from './type';
|
import type { RequestInstanceState } from './type';
|
||||||
|
|
||||||
const isHttpProxy = import.meta.env.DEV && import.meta.env.VITE_HTTP_PROXY === 'Y';
|
const isHttpProxy = import.meta.env.DEV && import.meta.env.VITE_HTTP_PROXY === 'Y';
|
||||||
@ -19,12 +19,8 @@ export const request = createFlatRequest<App.Service.Response, RequestInstanceSt
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
async onRequest(config) {
|
async onRequest(config) {
|
||||||
const { headers } = config;
|
const Authorization = getAuthorization();
|
||||||
|
Object.assign(config.headers, { Authorization });
|
||||||
// set token
|
|
||||||
const token = localStg.get('token');
|
|
||||||
const Authorization = token ? `Bearer ${token}` : null;
|
|
||||||
Object.assign(headers, { Authorization });
|
|
||||||
|
|
||||||
return config;
|
return config;
|
||||||
},
|
},
|
||||||
@ -83,15 +79,13 @@ export const request = createFlatRequest<App.Service.Response, RequestInstanceSt
|
|||||||
// when the backend response code is in `expiredTokenCodes`, it means the token is expired, and refresh token
|
// when the backend response code is in `expiredTokenCodes`, it means the token is expired, and refresh token
|
||||||
// the api `refreshToken` can not return error code in `expiredTokenCodes`, otherwise it will be a dead loop, should return `logoutCodes` or `modalLogoutCodes`
|
// the api `refreshToken` can not return error code in `expiredTokenCodes`, otherwise it will be a dead loop, should return `logoutCodes` or `modalLogoutCodes`
|
||||||
const expiredTokenCodes = import.meta.env.VITE_SERVICE_EXPIRED_TOKEN_CODES?.split(',') || [];
|
const expiredTokenCodes = import.meta.env.VITE_SERVICE_EXPIRED_TOKEN_CODES?.split(',') || [];
|
||||||
if (expiredTokenCodes.includes(responseCode) && !request.state.isRefreshingToken) {
|
if (expiredTokenCodes.includes(responseCode)) {
|
||||||
request.state.isRefreshingToken = true;
|
const success = await handleExpiredRequest(request.state);
|
||||||
|
if (success) {
|
||||||
|
const Authorization = getAuthorization();
|
||||||
|
Object.assign(response.config.headers, { Authorization });
|
||||||
|
|
||||||
const refreshConfig = await handleRefreshToken(response.config);
|
return instance.request(response.config) as Promise<AxiosResponse>;
|
||||||
|
|
||||||
request.state.isRefreshingToken = false;
|
|
||||||
|
|
||||||
if (refreshConfig) {
|
|
||||||
return instance.request(refreshConfig) as Promise<AxiosResponse>;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,34 +1,44 @@
|
|||||||
import type { AxiosRequestConfig } from 'axios';
|
|
||||||
import { useAuthStore } from '@/store/modules/auth';
|
import { useAuthStore } from '@/store/modules/auth';
|
||||||
import { localStg } from '@/utils/storage';
|
import { localStg } from '@/utils/storage';
|
||||||
import { fetchRefreshToken } from '../api';
|
import { fetchRefreshToken } from '../api';
|
||||||
import type { RequestInstanceState } from './type';
|
import type { RequestInstanceState } from './type';
|
||||||
|
|
||||||
/**
|
export function getAuthorization() {
|
||||||
* refresh token
|
const token = localStg.get('token');
|
||||||
*
|
const Authorization = token ? `Bearer ${token}` : null;
|
||||||
* @param axiosConfig - request config when the token is expired
|
|
||||||
*/
|
return Authorization;
|
||||||
export async function handleRefreshToken(axiosConfig: AxiosRequestConfig) {
|
}
|
||||||
|
|
||||||
|
/** refresh token */
|
||||||
|
async function handleRefreshToken() {
|
||||||
const { resetStore } = useAuthStore();
|
const { resetStore } = useAuthStore();
|
||||||
|
|
||||||
const refreshToken = localStg.get('refreshToken') || '';
|
const rToken = localStg.get('refreshToken') || '';
|
||||||
const { error, data } = await fetchRefreshToken(refreshToken);
|
const { error, data } = await fetchRefreshToken(rToken);
|
||||||
if (!error) {
|
if (!error) {
|
||||||
localStg.set('token', data.token);
|
localStg.set('token', data.token);
|
||||||
localStg.set('refreshToken', data.refreshToken);
|
localStg.set('refreshToken', data.refreshToken);
|
||||||
|
return true;
|
||||||
const config = { ...axiosConfig };
|
|
||||||
if (config.headers) {
|
|
||||||
config.headers.Authorization = data.token;
|
|
||||||
}
|
|
||||||
|
|
||||||
return config;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
resetStore();
|
resetStore();
|
||||||
|
|
||||||
return null;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function handleExpiredRequest(state: RequestInstanceState) {
|
||||||
|
if (!state.refreshTokenFn) {
|
||||||
|
state.refreshTokenFn = handleRefreshToken();
|
||||||
|
}
|
||||||
|
|
||||||
|
const success = await state.refreshTokenFn;
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
state.refreshTokenFn = null;
|
||||||
|
}, 1000);
|
||||||
|
|
||||||
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function showErrorMsg(state: RequestInstanceState, message: string) {
|
export function showErrorMsg(state: RequestInstanceState, message: string) {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
export interface RequestInstanceState {
|
export interface RequestInstanceState {
|
||||||
/** whether the request is refreshing token */
|
/** whether the request is refreshing token */
|
||||||
isRefreshingToken: boolean;
|
refreshTokenFn: Promise<boolean> | null;
|
||||||
/** the request error message stack */
|
/** the request error message stack */
|
||||||
errMsgStack: string[];
|
errMsgStack: string[];
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user