chore: establish local platform baseline

This commit is contained in:
Codex Local
2026-08-26 06:41:54 +08:00
commit 29bdf4900f
575 changed files with 95644 additions and 0 deletions
+54
View File
@@ -0,0 +1,54 @@
import { UserManager, WebStorageStateStore, type User } from "oidc-client-ts";
import { runtimeConfig } from "../runtimeConfig";
const origin = window.location.origin;
export const userManager = new UserManager({
authority: runtimeConfig.oidcAuthority,
client_id: runtimeConfig.oidcClientId,
redirect_uri: `${origin}/auth/callback`,
post_logout_redirect_uri: origin,
response_type: "code",
scope: "openid profile",
monitorSession: false,
automaticSilentRenew: true,
accessTokenExpiringNotificationTimeInSeconds: 60,
userStore: new WebStorageStateStore({ store: window.sessionStorage })
});
let callbackPromise: Promise<User | undefined> | undefined;
type SigninState = {
returnTo?: unknown;
};
export function startSignin(): Promise<void> {
return userManager.signinRedirect({
state: { returnTo: currentRelativeURL() }
});
}
export async function completeSigninIfNeeded(): Promise<void> {
if (window.location.pathname !== "/auth/callback") return;
callbackPromise ??= userManager.signinRedirectCallback();
const user = await callbackPromise;
const returnURL = safeReturnURL(user?.state);
window.history.replaceState({}, document.title, returnURL);
window.dispatchEvent(new PopStateEvent("popstate", { state: { returnURL } }));
}
function currentRelativeURL(): string {
return `${window.location.pathname}${window.location.search}${window.location.hash}`;
}
function safeReturnURL(state: unknown): string {
const returnTo = (state as SigninState | undefined)?.returnTo;
if (typeof returnTo !== "string" || !returnTo.startsWith("/") || returnTo.startsWith("//")) return "/";
try {
const target = new URL(returnTo, window.location.origin);
if (target.origin !== window.location.origin || target.pathname === "/auth/callback") return "/";
return `${target.pathname}${target.search}${target.hash}`;
} catch {
return "/";
}
}
+92
View File
@@ -0,0 +1,92 @@
import { useCallback, useEffect, useState } from "react";
import type { User } from "oidc-client-ts";
import { APIRequestError, AUTHENTICATION_REQUIRED_EVENT, platformApi, type CurrentUser } from "../api/client";
import { completeSigninIfNeeded, startSignin, userManager } from "./oidc";
type AuthState = {
loading: boolean;
oidcUser?: User;
currentUser?: CurrentUser;
error?: string;
};
export function useAuth() {
const [state, setState] = useState<AuthState>({ loading: true });
const loadUser = useCallback(async (user?: User | null) => {
const currentOIDCUser = user ?? (await userManager.getUser());
if (!currentOIDCUser || currentOIDCUser.expired) {
if (currentOIDCUser?.expired) {
await userManager.removeUser();
setState({ loading: false, error: "登录状态已过期,请重新登录" });
} else {
setState({ loading: false });
}
return;
}
try {
const response = await platformApi.currentUser(currentOIDCUser.access_token);
setState({ loading: false, oidcUser: currentOIDCUser, currentUser: response.data });
} catch (error) {
if (error instanceof APIRequestError && error.status === 401) {
await userManager.removeUser();
setState({ loading: false, error: "登录状态已经失效,请重新登录" });
return;
}
setState({
loading: false,
oidcUser: currentOIDCUser,
error: error instanceof Error ? error.message : "无法读取当前用户"
});
}
}, []);
useEffect(() => {
let active = true;
let authenticationFailureInProgress = false;
const initialize = async () => {
try {
await completeSigninIfNeeded();
if (active) await loadUser();
} catch (error) {
if (active) {
setState({ loading: false, error: error instanceof Error ? error.message : "登录回调处理失败" });
}
}
};
const onUserLoaded = (user: User) => { if (active) void loadUser(user); };
const onUserUnloaded = () => { if (active) setState({ loading: false }); };
const clearInvalidSession = (message: string) => {
if (!active || authenticationFailureInProgress) return;
authenticationFailureInProgress = true;
void userManager.removeUser().finally(() => {
authenticationFailureInProgress = false;
if (active) setState({ loading: false, error: message });
});
};
const onAccessTokenExpired = () => clearInvalidSession("登录状态已过期,请重新登录");
const onSilentRenewError = () => clearInvalidSession("登录续期失败,请重新登录");
const onAuthenticationRequired = () => clearInvalidSession("登录状态已经失效,请重新登录");
userManager.events.addUserLoaded(onUserLoaded);
userManager.events.addUserUnloaded(onUserUnloaded);
userManager.events.addAccessTokenExpired(onAccessTokenExpired);
userManager.events.addSilentRenewError(onSilentRenewError);
window.addEventListener(AUTHENTICATION_REQUIRED_EVENT, onAuthenticationRequired);
void initialize();
return () => {
active = false;
userManager.events.removeUserLoaded(onUserLoaded);
userManager.events.removeUserUnloaded(onUserUnloaded);
userManager.events.removeAccessTokenExpired(onAccessTokenExpired);
userManager.events.removeSilentRenewError(onSilentRenewError);
window.removeEventListener(AUTHENTICATION_REQUIRED_EVENT, onAuthenticationRequired);
};
}, [loadUser]);
return {
...state,
login: () => startSignin(),
logout: () => userManager.signoutRedirect(),
retry: () => loadUser(state.oidcUser)
};
}