---
id: router.auth-before-load
kind: recipe
product: router
framework: react
locale: zh-CN
revision: 1
sourceCheckedOn: "2026-08-03"
versionRange: "^1"
verifiedAgainst: "@tanstack/react-router@1.170.18"
contentModel: 2
packages:
  - "@tanstack/react-router"
tasks:
  - "protect-route-group"
  - "redirect-to-login"
  - "preserve-return-url"
sourceRefs:
  - "https://tanstack.com/router/latest/docs/framework/react/guide/authenticated-routes"
  - "https://tanstack.com/router/latest/docs/framework/react/guide/router-context"
---

# 用 beforeLoad 保护路由子树

> 在 pathless layout 中读取类型化认证 Context，阻止未登录用户加载子路由，并保留经过约束的回跳 URL。

## 执行契约

- **适用场景:** 一组 Router 页面必须在任何子 Loader 执行前要求有效登录会话。
- **不要使用:** 不要把客户端 beforeLoad 当作服务端资源授权，也不要只靠隐藏导航链接。
- **前置检查:** 确认认证状态如何进入类型化 Router Context、私有路由的共同父级以及允许的登录回跳目标。
- **验证结果:** 测试未登录直达、登录刷新、会话过期和恶意外部回跳，并证明子 Loader 与服务端入口都在各自边界拒绝未授权请求。
- **失败模式:** 若页面先请求私有数据再跳登录，门禁放得太低或异步认证未在父 beforeLoad 中完成；上移到保护子树的最近共同父级。
- **安全边界:** 验证 redirect 目标为本站安全路径，防止开放重定向；所有私有 Server Function、Server Route 和数据源必须重新鉴权与授权。

## 决策顺序

先确认认证状态如何进入 Router Context，再选择保护整棵子树的最近 pathless layout。父级 beforeLoad 在子级之前执行；无会话时 throw redirect，有会话时返回最小 user 上下文。不要在每个叶子路由复制检查。

## 最小实现

使用 beforeLoad 参数中的 location.href 记录真实目标。登录处理器只允许站内相对路径或经过同源验证的目标；外部 URL 必须回退到固定首页。

File: `src/routes/_authenticated.tsx`

```tsx
import { Outlet, createFileRoute, redirect } from '@tanstack/react-router'

export const Route = createFileRoute('/_authenticated')({
  beforeLoad: ({ context, location }) => {
    if (!context.auth.user) {
      throw redirect({
        to: '/login',
        search: { redirect: location.href },
      })
    }
    return { user: context.auth.user }
  },
  component: () => <Outlet />,
})
```

## 验证矩阵

验证未登录直达不会运行子 Loader；登录用户刷新正常；会话过期后下一次导航回到登录；外部 redirect 被拒绝；服务端数据入口在绕过 UI 直接调用时仍独立返回未授权。

## Official sources

- https://tanstack.com/router/latest/docs/framework/react/guide/authenticated-routes
- https://tanstack.com/router/latest/docs/framework/react/guide/router-context
