From 472467803572b1009a76ada9f67d725705c0b76b Mon Sep 17 00:00:00 2001 From: nav Date: Wed, 13 May 2026 08:18:01 +0000 Subject: [PATCH] feat(frontend): require center API key on login/auth calls --- src/auth/AuthContext.tsx | 8 ++++---- src/auth/auth-context.ts | 2 +- src/lib/auth-storage.ts | 1 + src/lib/center-auth-client.ts | 17 +++++++++-------- src/pages/LoginPage.tsx | 8 +++++++- 5 files changed, 22 insertions(+), 14 deletions(-) diff --git a/src/auth/AuthContext.tsx b/src/auth/AuthContext.tsx index 7adfd2c..24b1b2d 100644 --- a/src/auth/AuthContext.tsx +++ b/src/auth/AuthContext.tsx @@ -13,15 +13,15 @@ export function AuthProvider({ children }: PropsWithChildren) { () => ({ session, isAuthed: !!session, - login: async (centerApiBase: string, email: string, password: string) => { - const next = await loginCenter(centerApiBase, { email, password }) + login: async (centerApiBase: string, centerApiKey: string, email: string, password: string) => { + const next = await loginCenter(centerApiBase, centerApiKey, { email, password }) setAuthSession(next) setSession(next) }, logout: async () => { if (session?.refreshToken) { try { - await logoutCenter(session.centerApiBase, session.refreshToken) + await logoutCenter(session.centerApiBase, session.centerApiKey, session.refreshToken) } catch { // noop } @@ -33,7 +33,7 @@ export function AuthProvider({ children }: PropsWithChildren) { if (!session) return null if (!isAccessTokenStale(session.accessToken)) return session.accessToken - const refreshed = await refreshCenter(session.centerApiBase, session.refreshToken) + const refreshed = await refreshCenter(session.centerApiBase, session.centerApiKey, session.refreshToken) const next: AuthSession = { ...session, accessToken: refreshed.accessToken, diff --git a/src/auth/auth-context.ts b/src/auth/auth-context.ts index 51c816e..f58db38 100644 --- a/src/auth/auth-context.ts +++ b/src/auth/auth-context.ts @@ -4,7 +4,7 @@ import type { AuthSession } from '../lib/auth-storage' export type AuthContextValue = { session: AuthSession | null isAuthed: boolean - login: (centerApiBase: string, email: string, password: string) => Promise + login: (centerApiBase: string, centerApiKey: string, email: string, password: string) => Promise logout: () => Promise ensureFreshToken: () => Promise } diff --git a/src/lib/auth-storage.ts b/src/lib/auth-storage.ts index 5267247..0429d0f 100644 --- a/src/lib/auth-storage.ts +++ b/src/lib/auth-storage.ts @@ -1,5 +1,6 @@ export type AuthSession = { centerApiBase: string + centerApiKey: string accessToken: string refreshToken: string tokenType: string diff --git a/src/lib/center-auth-client.ts b/src/lib/center-auth-client.ts index 6225802..5d34915 100644 --- a/src/lib/center-auth-client.ts +++ b/src/lib/center-auth-client.ts @@ -19,7 +19,7 @@ type RefreshResponse = { tokenType: string } -function centerClient(centerApiBase: string) { +function centerClient(centerApiBase: string, centerApiKey: string) { const client = axios.create({ baseURL: centerApiBase, timeout: 10000, @@ -27,6 +27,7 @@ function centerClient(centerApiBase: string) { client.interceptors.request.use((request) => { const requestId = crypto.randomUUID() + request.headers['x-api-key'] = centerApiKey request.headers['x-request-id'] = requestId request.headers['x-client-name'] = 'fabric-frontend' return request @@ -35,16 +36,16 @@ function centerClient(centerApiBase: string) { return client } -export async function loginCenter(centerApiBase: string, payload: LoginPayload): Promise { - const res = await centerClient(centerApiBase).post('/auth/login', payload) - return { ...res.data, centerApiBase } +export async function loginCenter(centerApiBase: string, centerApiKey: string, payload: LoginPayload): Promise { + const res = await centerClient(centerApiBase, centerApiKey).post('/auth/login', payload) + return { ...res.data, centerApiBase, centerApiKey } } -export async function refreshCenter(centerApiBase: string, refreshToken: string): Promise { - const res = await centerClient(centerApiBase).post('/auth/refresh', { refreshToken }) +export async function refreshCenter(centerApiBase: string, centerApiKey: string, refreshToken: string): Promise { + const res = await centerClient(centerApiBase, centerApiKey).post('/auth/refresh', { refreshToken }) return res.data } -export async function logoutCenter(centerApiBase: string, refreshToken: string): Promise { - await centerClient(centerApiBase).post('/auth/logout', { refreshToken }) +export async function logoutCenter(centerApiBase: string, centerApiKey: string, refreshToken: string): Promise { + await centerClient(centerApiBase, centerApiKey).post('/auth/logout', { refreshToken }) } diff --git a/src/pages/LoginPage.tsx b/src/pages/LoginPage.tsx index e6d32f4..0880215 100644 --- a/src/pages/LoginPage.tsx +++ b/src/pages/LoginPage.tsx @@ -7,6 +7,7 @@ export default function LoginPage() { const navigate = useNavigate() const { login, isAuthed, session } = useAuth() const [centerApiBase, setCenterApiBase] = useState('http://localhost:7001/api') + const [centerApiKey, setCenterApiKey] = useState('') const [email, setEmail] = useState('') const [password, setPassword] = useState('') const [error, setError] = useState('') @@ -15,7 +16,7 @@ export default function LoginPage() { e.preventDefault() setError('') try { - await login(centerApiBase.trim(), email, password) + await login(centerApiBase.trim(), centerApiKey.trim(), email, password) navigate('/workspace') } catch { setError('登录失败,请检查账号密码') @@ -32,6 +33,11 @@ export default function LoginPage() { onChange={(e) => setCenterApiBase(e.target.value)} placeholder="Center API Base (e.g. http://localhost:7001/api)" /> + setCenterApiKey(e.target.value)} + placeholder="Center API Key" + /> setEmail(e.target.value)} placeholder="Email" type="email" />