环境变量与安全机制
6.6 Middleware 路由保护
Tip
学会用Middleware保护敏感路由,实现服务端验证,避免未授权访问。
1. 为什么要学这个?
你做了一个博客系统,有一个后台管理页面/admin。你在首页写了代码:if (!user.isAdmin) return null;来隐藏入口按钮。你觉得很安全。
直到有一天,一个竞争对手直接在地址栏输入了https://your-blog.com/admin。页面直接跳了出来,他不仅能看,还能删你的文章。
前端隐藏只是掩耳盗铃——任何人都能直接访问URL,删光你的数据。
2. 核心概念
2.1 Middleware - 中间件保护机制
技术定义:Next.js Middleware是全栈框架中的拦截层,运行在每一个HTTP请求到达渲染引擎或静态资源获取之前。它在边缘运行时(Edge Runtime)执行,允许开发者通过检查Cookies、Headers或Auth Token来实现全局的身份认证、路径重定向及地理位置过滤。
sequenceDiagram
participant User as "用户(Client)"
participant Middleware as "保安(Middleware)"
participant Page as "机密页面(/admin)"
participant Login as "登录页(/login)"
User->>Middleware: 1. 偷袭可以直接访问/admin吗?
Note over Middleware: 检查是否携带Session Token
alt 没带证件
Middleware-->>User: 2. 滚!重定向到/login
else 带了证件
Middleware->>Page: 2. 放行
Page-->>User: 3. 返回页面内容
end
3. 代码实战
在项目根目录(app同级)创建middleware.ts:
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
// 1. 指定拦截哪些路径(Matcher)
export const config = {
matcher: ['/admin/:path*', '/dashboard/:path*'],
}
export function middleware(request: NextRequest) {
// 2. 检查是否有Token(Cookie)
const token = request.cookies.get('session_token')
// 3. 如果没Token,踢回登录页
if (!token) {
return NextResponse.redirect(new URL('/login', request.url))
}
// 4. 甚至可以调API验证Token有效性...
// 5. 放行
return NextResponse.next()
}
4. 应用场景
| 🎯 场景 | 动作 |
|---|---|
| 后台保护 | 访问/dashboard或/admin时,检查是否登录 |
| 国际化(i18n) | 访问/about时,自动根据浏览器语言跳到/zh/about或/en/about |
| A/B测试 | 随机把50%用户重定向到新版页面 |
5. 避坑指南
| ✅ 推荐做法 | ❌ 禁忌 |
|---|---|
| 使用Matcher过滤路径 | 拦截全局所有请求(导致静态图片加载变慢) |
| 只做轻量级校验 | 在中间件里查数据库(中间件运行在边缘节点,可能连不上数据库且超时) |
| 配合前端重定向 | 只靠前端useEffect跳转(会有闪屏,且不安全) |
6. 真实案例
Story
2019年,第一美国金融公司8.85亿份文件泄露
First American Financial Corp是美国最大的产权保险公司之一。漏洞原理:IDOR(不安全的直接对象引用)。他们的网站允许通过URL查看文件,类似website.com/document?id=100。竟然没有任何中间件验证来检查"当前用户是否有权查看文件#100"。只要你把URL里的数字改成101,就能看到别人的房产证、银行账号和社保号。后果:8.85亿份敏感文件裸露,公司股价暴跌,面临SEC严厉指控。
Vibe心法:不要指望用户会乖乖点击链接——敏感地址必须在Middleware层安排保安,无验证不放行。
7. 本章小结
- 🛡️ 保安机制:Middleware是请求到达页面之前的最后一道防线
- 🔐 服务端验证:不要依赖前端
useRouter跳转,那只是为了体验,不是为了安全 - 🚫 最小权限:默认拦截所有敏感路由,只有验证通过才放行