diff --git a/src/server/index.ts b/src/server/index.ts index ef4cf4d..a2ae868 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -150,6 +150,7 @@ function deriveActionLabel(method: string, path: string): string { const p = path.replace(/\/+$/, ''); const rules: ReadonlyArray<[RegExp, string]> = [ [/^\/api\/auth\/login$/, '登录'], + [/^\/api\/auth\/logout$/, '登出'], [/^\/api\/assessments\/run$/, '运行评估(创建/重评)'], [/^\/api\/assessments\/[^/]+\/submit$/, '申报报送风控'], [/^\/api\/assessments\/[^/]+\/resubmit$/, '驳回后重新提交'], @@ -319,6 +320,15 @@ app.post('/api/auth/login', async (c) => { return c.json({ token, username, role }); }); +/** + * POST /api/auth/logout + * 登出:无状态 JWT 由客户端丢弃 token 即可,本端点仅用于留痕审计(记录谁/何时登出)。 + * 需携带有效 token,审计中间件据此解析操作人。 + */ +app.post('/api/auth/logout', (c) => { + return c.json({ ok: true }); +}); + /** LLM 启用状态(不泄露密钥),供前端/调试查询。 */ app.get('/api/llm/status', (c) => { const cfg = getLlmConfig(); diff --git a/web/src/stores/authStore.ts b/web/src/stores/authStore.ts index 2edbc80..2dd3bf0 100644 --- a/web/src/stores/authStore.ts +++ b/web/src/stores/authStore.ts @@ -95,6 +95,14 @@ export const useAuthStore = create((set) => ({ }, logout: () => { + // 先通知后端留痕(登出审计),再清除本地令牌;失败不阻塞登出。 + try { + const token = localStorage.getItem('risk-agent-token'); + void fetch(`${API_BASE}/api/auth/logout`, { + method: 'POST', + headers: { 'Content-Type': 'application/json', ...(token ? { Authorization: `Bearer ${token}` } : {}) }, + }).catch(() => undefined); + } catch { /* ignore */ } saveToStorage(null); try { localStorage.removeItem('risk-agent-token'); localStorage.removeItem('risk-agent-uid'); } catch { /* ignore */ } set({ isAuthenticated: false, user: null, error: null });