hyapp-admin-platform/external-admin/src/auth/ExternalAuthProvider.jsx

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;
}