diff --git a/frontend/src/router/RedirectIfAuthed.tsx b/frontend/src/router/RedirectIfAuthed.tsx
new file mode 100644
index 0000000..29d4823
--- /dev/null
+++ b/frontend/src/router/RedirectIfAuthed.tsx
@@ -0,0 +1,25 @@
+// REQ-USR-004: /login 守卫(BR2)。已登录访问登录页 → 回 from 或 /。
+import type { ReactNode } from 'react';
+import { Navigate, useLocation } from 'react-router-dom';
+import { useAppSelector } from '../store/hooks';
+
+interface RedirectIfAuthedProps {
+ children: ReactNode;
+}
+
+/**
+ * 已登录态判定(D:仅 token 即视为已登录,与 RequireAuth 的「token 存在即非未登录」语义对齐;
+ * 避免 token 已持久化、user 尚在拉取时登录页与守卫之间互相弹跳)。
+ * 已登录 → 重定向到 location.state.from(来源)或 /;否则渲染 children(LoginPage)。
+ */
+export default function RedirectIfAuthed({ children }: RedirectIfAuthedProps) {
+ const token = useAppSelector((s) => s.auth.token);
+ const location = useLocation();
+
+ if (token) {
+ const from = (location.state as { from?: string } | null)?.from;
+ return ;
+ }
+
+ return <>{children}>;
+}
diff --git a/frontend/tests/unit/RedirectIfAuthed.test.tsx b/frontend/tests/unit/RedirectIfAuthed.test.tsx
new file mode 100644
index 0000000..f1debfc
--- /dev/null
+++ b/frontend/tests/unit/RedirectIfAuthed.test.tsx
@@ -0,0 +1,60 @@
+// REQ-USR-004: RedirectIfAuthed —— 已登录访问 /login 回主页(BR2)
+import { describe, it, expect } from 'vitest';
+import { screen } from '@testing-library/react';
+import { Routes, Route } from 'react-router-dom';
+import { renderShell } from './renderShell';
+import RedirectIfAuthed from '../../src/router/RedirectIfAuthed';
+
+function LoginScreen() {
+ return
login-screen
;
+}
+function HomeSentinel() {
+ return home-sentinel
;
+}
+function UsersSentinel() {
+ return users-sentinel
;
+}
+
+function renderTree(
+ initialEntries: { pathname: string; state?: unknown }[] | string[],
+ preloadedAuth?: Parameters[1]['preloadedAuth'],
+) {
+ return renderShell(
+
+
+
+
+ }
+ />
+ } />
+ } />
+ ,
+ { initialEntries: initialEntries as never, preloadedAuth },
+ );
+}
+
+const READY_USER = {
+ token: 't',
+ user: { id: 1, sUserName: '朱子纯', sUserType: '超级管理员', sLanguage: '中文' },
+};
+
+describe('RedirectIfAuthed', () => {
+ it('renders children when unauthenticated', () => {
+ renderTree(['/login'], { token: null, user: null });
+ expect(screen.getByTestId('login-screen')).toBeInTheDocument();
+ });
+
+ it('redirects to / when already authenticated', () => {
+ renderTree(['/login'], READY_USER);
+ expect(screen.getByTestId('home-sentinel')).toBeInTheDocument();
+ expect(screen.queryByTestId('login-screen')).not.toBeInTheDocument();
+ });
+
+ it('redirects to from when present', () => {
+ renderTree([{ pathname: '/login', state: { from: '/usr/users' } }], READY_USER);
+ expect(screen.getByTestId('users-sentinel')).toBeInTheDocument();
+ });
+});