feat(auth): 登出留痕审计

- 原登出为纯前端清 token,不发请求,故无记录
- 新增 POST /api/auth/logout 端点(无状态,仅供审计留痕),deriveActionLabel 加「登出」标签
- 前端 logout 先带 token 通知后端再清本地,失败不阻塞
- 审计中间件经 authMiddleware 解析操作人,记录谁/何时登出
This commit is contained in:
freedakgmail
2026-06-14 11:15:00 +08:00
parent 5ae33502f9
commit 0fd8489c22
2 changed files with 18 additions and 0 deletions
+10
View File
@@ -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();
+8
View File
@@ -95,6 +95,14 @@ export const useAuthStore = create<AuthState>((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 });