74 lines
2.4 KiB
JavaScript
74 lines
2.4 KiB
JavaScript
import { createContext, useCallback, useContext, useEffect, useMemo, useState } from "react";
|
|
import { changeExternalPassword, getExternalSession, loginExternal, logoutExternal } from "../api/auth.js";
|
|
import { ExternalApiError, setExternalUnauthorizedHandler } from "../api/client.js";
|
|
|
|
const ExternalAuthContext = createContext(null);
|
|
|
|
export function ExternalAuthProvider({ children }) {
|
|
const [session, setSession] = useState(null);
|
|
const [initializing, setInitializing] = useState(true);
|
|
const [initializationError, setInitializationError] = useState("");
|
|
|
|
const refresh = useCallback(async () => {
|
|
setInitializationError("");
|
|
try {
|
|
const nextSession = await getExternalSession();
|
|
setSession(nextSession);
|
|
return nextSession;
|
|
} catch (error) {
|
|
setSession(null);
|
|
if (!(error instanceof ExternalApiError && error.status === 401)) {
|
|
setInitializationError(error.message || "会话校验失败");
|
|
}
|
|
return null;
|
|
} finally {
|
|
setInitializing(false);
|
|
}
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
refresh();
|
|
}, [refresh]);
|
|
|
|
useEffect(() => {
|
|
// Any protected request returning 401 invalidates the entire external session; it never mutates the main-admin session.
|
|
return setExternalUnauthorizedHandler(() => setSession(null));
|
|
}, []);
|
|
|
|
const login = useCallback(async (credentials) => {
|
|
const nextSession = await loginExternal(credentials);
|
|
setSession(nextSession);
|
|
return nextSession;
|
|
}, []);
|
|
|
|
const logout = useCallback(async () => {
|
|
try {
|
|
await logoutExternal();
|
|
} finally {
|
|
setSession(null);
|
|
}
|
|
}, []);
|
|
|
|
const changePassword = useCallback(async (payload) => {
|
|
const responseSession = await changeExternalPassword(payload);
|
|
const nextSession = responseSession?.appCode ? responseSession : await getExternalSession();
|
|
setSession({ ...nextSession, passwordChangeRequired: false });
|
|
return nextSession;
|
|
}, []);
|
|
|
|
const value = useMemo(
|
|
() => ({ changePassword, initializationError, initializing, login, logout, refresh, session }),
|
|
[changePassword, initializationError, initializing, login, logout, refresh, session]
|
|
);
|
|
|
|
return <ExternalAuthContext.Provider value={value}>{children}</ExternalAuthContext.Provider>;
|
|
}
|
|
|
|
export function useExternalAuth() {
|
|
const context = useContext(ExternalAuthContext);
|
|
if (!context) {
|
|
throw new Error("useExternalAuth must be used inside ExternalAuthProvider");
|
|
}
|
|
return context;
|
|
}
|