Merge remote-tracking branch 'origin/ji' into ji
This commit is contained in:
commit
143e0478ef
2 files changed
+46
-11
No files matched your search
@@ -1,4 +1,8 @@
|
|||||||
import { getAuthorizationHeaderValue } from "@/core/auth";
|
import {
|
||||||
|
clearStoredAuth,
|
||||||
|
getAuthorizationHeaderValue,
|
||||||
|
getStoredAuth,
|
||||||
|
} from "@/core/auth";
|
||||||
import { withCsrfHeaders } from "./csrf";
|
import { withCsrfHeaders } from "./csrf";
|
||||||
|
|
||||||
function withAuthHeaders(headers?: HeadersInit): Headers {
|
function withAuthHeaders(headers?: HeadersInit): Headers {
|
||||||
@@ -8,13 +12,40 @@ function withAuthHeaders(headers?: HeadersInit): Headers {
|
|||||||
next.set("Authorization", authHeader);
|
next.set("Authorization", authHeader);
|
||||||
}
|
}
|
||||||
return next;
|
return next;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function apiFetch(input: RequestInfo | URL, init?: RequestInit) {
|
function requestUrl(input: RequestInfo | URL): string {
|
||||||
return fetch(input, {
|
if (typeof input === "string") return input;
|
||||||
|
if (input instanceof URL) return input.href;
|
||||||
|
return (input as Request).url ?? "";
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function apiFetch(input: RequestInfo | URL, init?: RequestInit) {
|
||||||
|
const response = await fetch(input, {
|
||||||
...init,
|
...init,
|
||||||
credentials: init?.credentials ?? "include",
|
credentials: init?.credentials ?? "include",
|
||||||
headers: withAuthHeaders(init?.headers),
|
headers: withAuthHeaders(init?.headers),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Session is considered lost ONLY when the backend actually answers 401.
|
||||||
|
// (Previously a stray localStorage change could log the user out client-side
|
||||||
|
// even though the session was still valid.) Auth endpoints are excluded so a
|
||||||
|
// failed/transient login attempt never wipes state, and we only act when we
|
||||||
|
// believed we were logged in — avoiding redirect loops on the login page.
|
||||||
|
if (response.status === 401) {
|
||||||
|
const url = requestUrl(input);
|
||||||
|
const isAuthEndpoint = url.includes("/api/v1/auth/");
|
||||||
|
if (!isAuthEndpoint && getStoredAuth()) {
|
||||||
|
clearStoredAuth();
|
||||||
|
if (
|
||||||
|
typeof window !== "undefined" &&
|
||||||
|
!window.location.hash.startsWith("#/login")
|
||||||
|
) {
|
||||||
|
window.location.replace("#/login");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -23,7 +23,12 @@ export function AuthSyncWatcher() {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
function handleStorage(event: StorageEvent) {
|
function handleStorage(event: StorageEvent) {
|
||||||
if (event.key !== null && event.key !== AUTH_STORAGE_KEY) {
|
// Only react to explicit changes of the auth key. Ignore unrelated keys
|
||||||
|
// AND `localStorage.clear()` (event.key === null) — embedded sub-apps /
|
||||||
|
// iframes wiping their own storage used to spuriously log the user out
|
||||||
|
// here even though the backend session was still valid. Genuine session
|
||||||
|
// loss is now detected centrally via 401 responses in apiFetch.
|
||||||
|
if (event.key !== AUTH_STORAGE_KEY) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const nextUserId = readUserId();
|
const nextUserId = readUserId();
|
||||||
@@ -31,12 +36,11 @@ export function AuthSyncWatcher() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
lastUserIdRef.current = nextUserId;
|
lastUserIdRef.current = nextUserId;
|
||||||
if (nextUserId === null) {
|
// Only resync on a genuine account switch in another tab (different,
|
||||||
window.location.replace("#/login");
|
// non-null user). Do NOT force a login redirect on null here.
|
||||||
|
if (nextUserId !== null) {
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
window.location.reload();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
window.addEventListener("storage", handleStorage);
|
window.addEventListener("storage", handleStorage);
|
||||||
|
|||||||
Reference in new issue
Block a user