mirror of
https://github.com/KwiTsukasa/kt-template-online-web.git
synced 2026-05-27 16:35:47 +08:00
fix(web): 修复 401 鉴权恢复跳转
This commit is contained in:
parent
99f5615144
commit
c54a7f4f36
@ -18,6 +18,7 @@ const ACCESS_CODES_KEY = "kt-admin-access-codes";
|
|||||||
const USER_INFO_KEY = "kt-admin-user-info";
|
const USER_INFO_KEY = "kt-admin-user-info";
|
||||||
|
|
||||||
let refreshPromise: Promise<string | null> | null = null;
|
let refreshPromise: Promise<string | null> | null = null;
|
||||||
|
let redirectingToAdminLogin = false;
|
||||||
|
|
||||||
const authClient = axios.create({
|
const authClient = axios.create({
|
||||||
baseURL: config.axiosBase,
|
baseURL: config.axiosBase,
|
||||||
@ -66,6 +67,9 @@ const buildAdminLoginUrl = (redirect: string) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const redirectToAdminLogin = () => {
|
export const redirectToAdminLogin = () => {
|
||||||
|
if (redirectingToAdminLogin) return;
|
||||||
|
|
||||||
|
redirectingToAdminLogin = true;
|
||||||
window.location.href = buildAdminLoginUrl(window.location.href);
|
window.location.href = buildAdminLoginUrl(window.location.href);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -10,9 +10,18 @@ import {
|
|||||||
export interface ApiResponse<T = any> {
|
export interface ApiResponse<T = any> {
|
||||||
code: number;
|
code: number;
|
||||||
data: T;
|
data: T;
|
||||||
|
message?: string;
|
||||||
msg: string;
|
msg: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type AuthRetryConfig = AxiosRequestConfig & {
|
||||||
|
_authRetried?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
type AuthHeaderMap = Record<string, unknown> & {
|
||||||
|
get?: (name: string) => unknown;
|
||||||
|
};
|
||||||
|
|
||||||
const request = axios.create({
|
const request = axios.create({
|
||||||
baseURL: config.axiosBase,
|
baseURL: config.axiosBase,
|
||||||
timeout: 1000 * 30,
|
timeout: 1000 * 30,
|
||||||
@ -27,6 +36,49 @@ export const post = <T = any>(url: string, data?: any, config?: AxiosRequestConf
|
|||||||
return request.post<any, ApiResponse<T>>(url, data, config);
|
return request.post<any, ApiResponse<T>>(url, data, config);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getAuthErrorMessage = (data?: Partial<ApiResponse>) => {
|
||||||
|
return data?.msg || data?.message || "登录已过期";
|
||||||
|
};
|
||||||
|
|
||||||
|
const getRequestAuthorization = (requestConfig?: AuthRetryConfig) => {
|
||||||
|
const headers = requestConfig?.headers as AuthHeaderMap | undefined;
|
||||||
|
|
||||||
|
if (!headers) return null;
|
||||||
|
if (typeof headers.get === "function") {
|
||||||
|
return headers.get("Authorization") || headers.get("authorization");
|
||||||
|
}
|
||||||
|
|
||||||
|
return headers.Authorization || headers.authorization;
|
||||||
|
};
|
||||||
|
|
||||||
|
const retryRequestWithFreshToken = async (requestConfig?: AuthRetryConfig) => {
|
||||||
|
if (!requestConfig || requestConfig._authRetried) return null;
|
||||||
|
|
||||||
|
const hasOldAccessToken = Boolean(
|
||||||
|
getStoredAccessToken() || getRequestAuthorization(requestConfig),
|
||||||
|
);
|
||||||
|
if (!hasOldAccessToken) return null;
|
||||||
|
|
||||||
|
requestConfig._authRetried = true;
|
||||||
|
clearPersistedAuth();
|
||||||
|
const accessToken = await refreshPersistedAuth();
|
||||||
|
|
||||||
|
if (!accessToken) return null;
|
||||||
|
|
||||||
|
requestConfig.headers = {
|
||||||
|
...(requestConfig.headers || {}),
|
||||||
|
Authorization: `Bearer ${accessToken}`,
|
||||||
|
};
|
||||||
|
|
||||||
|
// 只有旧 accessToken 过期时才尝试刷新并重放一次,未登录 401 直接去 Admin。
|
||||||
|
return request.request(requestConfig);
|
||||||
|
};
|
||||||
|
|
||||||
|
const redirectAfterAuthExpired = () => {
|
||||||
|
clearPersistedAuth();
|
||||||
|
redirectToAdminLogin();
|
||||||
|
};
|
||||||
|
|
||||||
request.interceptors.request.use(async (requestConfig) => {
|
request.interceptors.request.use(async (requestConfig) => {
|
||||||
let accessToken = getStoredAccessToken();
|
let accessToken = getStoredAccessToken();
|
||||||
|
|
||||||
@ -42,19 +94,25 @@ request.interceptors.request.use(async (requestConfig) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
request.interceptors.response.use(
|
request.interceptors.response.use(
|
||||||
(response) => {
|
async (response) => {
|
||||||
if (response.data?.code === 401) {
|
if (response.data?.code === 401) {
|
||||||
clearPersistedAuth();
|
const retryResponse = await retryRequestWithFreshToken(response.config as AuthRetryConfig);
|
||||||
redirectToAdminLogin();
|
if (retryResponse) return retryResponse;
|
||||||
return Promise.reject(new Error(response.data?.msg || "登录已过期"));
|
|
||||||
|
redirectAfterAuthExpired();
|
||||||
|
return Promise.reject(new Error(getAuthErrorMessage(response.data)));
|
||||||
}
|
}
|
||||||
|
|
||||||
return response.data;
|
return response.data;
|
||||||
},
|
},
|
||||||
(error) => {
|
async (error) => {
|
||||||
if (axios.isAxiosError(error) && error.response?.status === 401) {
|
if (axios.isAxiosError(error) && error.response?.status === 401) {
|
||||||
clearPersistedAuth();
|
const retryResponse = await retryRequestWithFreshToken(
|
||||||
redirectToAdminLogin();
|
error.config as AuthRetryConfig | undefined,
|
||||||
|
);
|
||||||
|
if (retryResponse) return retryResponse;
|
||||||
|
|
||||||
|
redirectAfterAuthExpired();
|
||||||
}
|
}
|
||||||
|
|
||||||
return Promise.reject(error);
|
return Promise.reject(error);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user