diff --git a/admin-frontend-vue/tests/live/task-40-live.test.ts b/admin-frontend-vue/tests/live/task-40-live.test.ts index 55fcf8e5..8a6ba2f6 100644 --- a/admin-frontend-vue/tests/live/task-40-live.test.ts +++ b/admin-frontend-vue/tests/live/task-40-live.test.ts @@ -130,3 +130,30 @@ test('test_task_040_live_smoke_dependency_failure_returns_actionable_message', { const user = parseCurrentUser(await (await authedFetch('/api/admin/current-user')).json()) assert.ok(roleKind(user.role) !== null) }) + +test('test_task_040_live_smoke_logout_clears_cookie', { skip: !HAS_CREDS }, async () => { + // 真实登出 E2E:POST /logout 下发清除 aiimage_token 的 Set-Cookie;清除后同源请求回到 401。 + const login = await fetch(`${BASE}/login`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ username: USER, password: PASS, deviceId: `${DEVICE}-e2e-logout` }), + }) + const loginBody = (await login.json()) as { success?: boolean; data?: { token?: string } } + assert.equal(loginBody.success, true) + const token = loginBody.data?.token || '' + assert.ok(token) + const cookie = `aiimage_token=${token}` + const out = await fetch(`${BASE}/logout`, { + method: 'POST', + headers: { Cookie: cookie, 'X-Requested-With': 'XMLHttpRequest' }, + }) + assert.equal(out.status, 200, '登出应返回 200 而非内置 LogoutFilter 的 204/500') + assert.equal(((await out.json()) as { success?: boolean }).success, true) + const clearCookies = typeof out.headers.getSetCookie === 'function' ? out.headers.getSetCookie() : [] + const clearHeader = clearCookies[0] || out.headers.get('set-cookie') || '' + assert.match(clearHeader, /aiimage_token=;/, '登出应清除 aiimage_token cookie') + assert.match(clearHeader, /Max-Age=0|Expires=Thu, 01 Jan 1970/) + const after = (await (await fetch(`${BASE}/api/admin/current-user`)).json()) as { success?: boolean; code?: number } + assert.equal(after.success, false) + assert.equal(after.code, 401) +}) diff --git a/backend-java/src/main/java/com/nanri/aiimage/config/SecurityConfig.java b/backend-java/src/main/java/com/nanri/aiimage/config/SecurityConfig.java index 53bf199e..4ce93389 100644 --- a/backend-java/src/main/java/com/nanri/aiimage/config/SecurityConfig.java +++ b/backend-java/src/main/java/com/nanri/aiimage/config/SecurityConfig.java @@ -19,6 +19,8 @@ public class SecurityConfig { return http .cors(Customizer.withDefaults()) .csrf(csrf -> csrf.disable()) + // 登出走 auth 模块 POST /logout(清 aiimage_token cookie),禁用内置 LogoutFilter + .logout(logout -> logout.disable()) .authorizeHttpRequests(auth -> auth.anyRequest().permitAll()) .httpBasic(Customizer.withDefaults()) .build();