中间件似乎是将Next.js应用的整个部分置于auth之后的最干净的方式,一个文件,一个配置,覆盖了路径下的所有内容。这种信心正是问题所在,因为matcherconfig应该定义"该路径下的所有内容",但它有几个特定的缺口,直到有人点击了一个完全跳过检查的嵌套路由时,这些缺口才会显示出来。
看起来很完整的设置
// middleware.ts
import { NextResponse } from 'next/server';
import { getToken } from 'next-auth/jwt';
export async function middleware(request: NextRequest) {
const token = await getToken({ req: request });
if (!token) {
return NextResponse.redirect(new URL('/login', request.url));
}
return NextResponse.next();
}
export const config = {
matcher: '/dashboard/:path*',
};
上面写着"保护下面的一切"/dashboard,"对于大多数人在开发过程中测试的路线,/dashboard, /dashboard/settings, /dashboard/analytics,它的工作完全符合预期。这种差距在路由组和并行/截取路由约定中表现得尤为明显,它们并不像文件夹结构直观显示的那样映射到URL路径上。
它真正断裂的地方
app/
├── (dashboard)/
│ ├── dashboard/
│ │ └── page.tsx → /dashboard
│ └── settings/
│ └── page.tsx → /settings (NOT /dashboard/settings!)
路由组,即带括号的文件夹,根本不会出现在URL中。一页在app/(dashboard)/settings/page.tsx提供给/settings,不是/dashboard/settings,即使它在视觉上位于代码库中看起来像您的仪表板文件夹的内部。Amatcher: '/dashboard/:path*'模式从不匹配/settings,因为就网址而言,它从来没有下过/dashboard首先。
这正是那种结构上的混乱,很容易从一个依赖于路由组进行布局的文件夹结构中延续下来,我在整个pixelanas.com上的Next.js模板,而不需要重新检查每个受保护页面的实际URL是否仍然在保护它的匹配器模式内,因为文件夹嵌套和URL嵌套已经悄悄地分开了。
第二个更微妙的差距:匹配模式和编码字符
Next.js自己的文档matcherconfig指出,值必须是文字字符串或简单模式,匹配器模式不支持任意的正则表达式特性,编码路径段周围的某些边缘情况或动态段中的异常字符可能无法匹配,从读取模式本身来看并不明显。像这样的路线/dashboard/reports/q1%2F2026(动态段中的编码斜杠)的行为可能不可预测,违背了看起来显然应该覆盖它的模式。
为什么这个没被发现
测试授权路由通常意味着手动点击受保护部分的主页面,即直接嵌套在明显路径下的页面,并确认重定向有效。从技术上讲,页面位于应用程序的同一概念部分,但由于路由组而位于匹配的URL模式之外,或者页面是后来添加的,并且碰巧解析到稍微超出匹配器覆盖范围的URL,所以永远不要根据auth gate进行手动测试,因为没有人会想到检查看起来不需要检查的URL。
解决方法:根据实际解析的URL,而不是文件夹结构,验证匹配器的覆盖范围
不要相信基于你的app/文件夹外观。对照您想要保护的每个页面的实际解析URL进行检查:
export const config = {
matcher: [
'/dashboard/:path*',
'/settings/:path*', // explicitly added once the real URL was checked
'/billing/:path*',
],
};
对于任何真正敏感的东西,更具防御性的模式是完全颠倒逻辑,默认情况下保护所有东西,并明确排除少数公共路径,而不是试图枚举每个受保护的路径,并希望列表随着应用程序的增长而保持完整:
export const config = {
matcher: [
'/((?!login|signup|api/public|_next/static|_next/image|favicon.ico).*)',
],
};
这种模式保护除了明确命名的公共路由之外的所有内容,这意味着路由组下新添加的页面或任何其他位置在默认情况下都受到保护,而不是静静地落在覆盖范围之外,直到有人注意到。
规则
应该根据应用程序的实际解析URL来验证中间件匹配器模式,而不是根据app/文件夹在视觉上是有组织的。路由组、并行路由和截取路由约定都以与文件夹嵌套不匹配的方式影响URL,而这正是看起来安静完整的匹配器模式不匹配的地方。
获取模板: https://www.iissbbs.com
去检查你自己的中间件匹配器,看看它应该保护的每个页面的真实URL,而不是文件夹结构。如果他们中的任何人使用路由组,这是值得今天仔细检查的。放下你在评论中发现的东西。