import { beforeEach, describe, expect, it, vi } from "vitest"; import type { User } from "../drizzle/schema"; vi.mock("./db", () => ({ getUserById: vi.fn() })); import * as db from "./db"; import { authenticateRequest, createSessionToken } from "./_core/auth"; import { ENV } from "./_core/env"; import { COOKIE_NAME } from "../shared/const"; function user(overrides: Partial = {}): User { const now = new Date(); return { id: 7, username: "session-user", passwordHash: "unused", name: "Session User", email: null, role: "user", isActive: 1, mustChangePassword: 0, sessionVersion: 3, createdAt: now, updatedAt: now, lastLoginAt: null, ...overrides }; } function requestWith(token: string) { return { headers: { cookie: `${COOKIE_NAME}=${token}` } } as Parameters[0]; } describe("会话即时失效", () => { beforeEach(() => { vi.clearAllMocks(); ENV.cookieSecret = "test-session-secret-with-at-least-32-chars"; }); it("有效账号与匹配版本可恢复会话", async () => { const current = user(); vi.mocked(db.getUserById).mockResolvedValue(current); const token = await createSessionToken(current); await expect(authenticateRequest(requestWith(token))).resolves.toMatchObject({ id: 7, sessionVersion: 3 }); }); it("改密或重置密码递增版本后旧会话立即失效", async () => { const token = await createSessionToken(user()); vi.mocked(db.getUserById).mockResolvedValue(user({ sessionVersion: 4 })); await expect(authenticateRequest(requestWith(token))).resolves.toBeNull(); }); it("账号被禁用后旧会话立即失效", async () => { const token = await createSessionToken(user()); vi.mocked(db.getUserById).mockResolvedValue(user({ isActive: 0 })); await expect(authenticateRequest(requestWith(token))).resolves.toBeNull(); }); });