030dcda9b4
/admin 加 RequireAdmin 后管理端原来无鉴权会 401。本次打通: - api.ts:JWT token 存 localStorage + 所有 /admin 调用带 Bearer + 401 清令牌广播登出; login/me;gatewayOnline 改用公开 /healthz(原 /billing 已转受保护会误判离线)。 - 修类型:Model.id number → string(模型 id 早已迁雪花字符串)。 - Login 登录门 + App 鉴权门(启动校验 me,无则登录页)+ AppShell 显示用户/登出。 实测(硬化网关):无 token /admin/models → 401;登录拿 token → 200 返回模型(string id)。 dev 未配 ADMIN_USER_IDS 时任意登录账号放行;生产须在白名单。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
40 lines
1.1 KiB
TypeScript
40 lines
1.1 KiB
TypeScript
import { useEffect, useState } from "react";
|
|
import { HashRouter } from "react-router-dom";
|
|
import { AppShell } from "./shell/AppShell";
|
|
import { Login } from "./Login";
|
|
import { me, clearToken, type AuthUser } from "./api";
|
|
|
|
// 用 HashRouter:纯静态托管/桌面内嵌都能深链,无需服务端路由配置。
|
|
export default function App() {
|
|
const [user, setUser] = useState<AuthUser | null>(null);
|
|
const [loading, setLoading] = useState(true);
|
|
|
|
useEffect(() => {
|
|
me()
|
|
.then(setUser)
|
|
.catch(() => setUser(null))
|
|
.finally(() => setLoading(false));
|
|
const onLogout = () => setUser(null);
|
|
window.addEventListener("sdx:logout", onLogout);
|
|
return () => window.removeEventListener("sdx:logout", onLogout);
|
|
}, []);
|
|
|
|
if (loading) {
|
|
return <div className="flex h-screen w-screen items-center justify-center text-sm text-gray-400">加载中…</div>;
|
|
}
|
|
if (!user) {
|
|
return <Login onAuthed={setUser} />;
|
|
}
|
|
return (
|
|
<HashRouter>
|
|
<AppShell
|
|
user={user}
|
|
onLogout={() => {
|
|
clearToken();
|
|
setUser(null);
|
|
}}
|
|
/>
|
|
</HashRouter>
|
|
);
|
|
}
|