如何在Next.js中间件中匹配动态路由并实现路由保护
问题原因
你当前代码用protectedRoutes.includes(path)做路径匹配,这是严格的字符串全等判断。/dashboard/sam32和数组里的/dashboard/:param*是完全不同的字符串,所以永远匹配失败,导致动态路由不会被标记为受保护路由。
解决方案
要匹配动态路由,需要用模式匹配逻辑(比如正则表达式)替代简单的字符串包含判断。下面是修改后的完整代码:
import { auth } from "@/auth" import { NextRequest, NextResponse } from 'next/server' // 1. 定义受保护路由的匹配模式(支持动态路由) const protectedRoutePatterns = [ /^\/dashboard\/[^/]+$/, // 匹配 /dashboard/xxx 这类单级动态路由 /^\/message\/.*$/ // 匹配 /message/ 下的所有子路由 ] const publicRoutes = ['/login', '/signup', '/'] export default async function middleware(req: NextRequest) { const path = req.nextUrl.pathname // 2. 检查当前路径是否匹配受保护路由模式 const isProtectedRoute = protectedRoutePatterns.some(pattern => pattern.test(path)) const isPublicRoute = publicRoutes.includes(path) const session = await auth(); // 3. 未登录用户访问受保护路由,重定向到登录页 if (isProtectedRoute && !session) { return NextResponse.redirect(new URL('/login', req.nextUrl)) } // 4. 已登录用户访问公共路由(除了首页),重定向到仪表盘 if (isPublicRoute && session?.user && path !== '/') { return NextResponse.redirect(new URL('/dashboard', req.nextUrl)) } return NextResponse.next() } export const config = { matcher: ['/((?!api|_next/static|_next/image|.*\\.png$).*)'], }
关键修改点
- 将受保护路由从字符串数组改为正则表达式数组,精准匹配动态路由格式:
/^\/dashboard\/[^/]+$/匹配/dashboard/后跟任意非斜杠字符的路径(如/dashboard/sam32)/^\/message\/.*$/匹配/message/下的所有子路由(包括/message/123、/message/inbox等)
- 用
Array.some()结合正则的test()方法判断路径是否符合受保护模式 - 修正公共路由重定向条件:原代码的
!req.nextUrl.pathname.startsWith('/')永远为false,改成path !== '/',避免已登录用户访问首页时被强制重定向
其他可选方案
如果不想写正则,也可以用路径前缀判断(适合简单场景):
const isProtectedRoute = path.startsWith('/dashboard/') || path.startsWith('/message/')
这种方式更简洁,但要注意如果存在/dashboard根路径(不带动态参数),需要单独排除或调整判断逻辑。
内容的提问来源于stack exchange,提问作者SamOlisa
相关产品推荐
相关产品推荐

