Next.js目录结构问题致中间件认证失效,仪表盘闪显
问题解决:Next.js双角色仪表盘未认证闪显+重定向失效
核心问题根源
- 客户端
ProtectedRoutes依赖useEffect执行重定向,组件会先渲染内容再跳转,必然出现闪显 - 目录内
middleware.ts路由匹配逻辑错误(比如staff中间件引用了client的路由配置),且Cookie校验名称不统一(组件查token,中间件查staff/client) - 目录级中间件的生效范围未正确配置,导致拦截逻辑失效
分步解决方案
1. 修复并统一中间件配置(关键)
将staff和client的认证逻辑合并到根目录app/middleware.ts,在请求到达页面之前完成拦截,彻底避免闪显:
import { NextResponse } from 'next/server'; import type { NextRequest } from 'next/server'; // 统一路由与Cookie规则 const ROUTE_RULES = { staff: { protectedPaths: ['/staff', '/staff/:path*'], loginPath: '/auth/staff', cookieKey: 'staff' }, client: { protectedPaths: ['/client', '/client/:path*'], loginPath: '/auth/client', cookieKey: 'client' } }; export function middleware(request: NextRequest) { const { pathname } = request.nextUrl; // 校验Staff路由权限 if (ROUTE_RULES.staff.protectedPaths.some(path => pathname.startsWith(path))) { const staffCookie = request.cookies.get(ROUTE_RULES.staff.cookieKey)?.value; let isAuthValid = false; if (staffCookie) { try { const userData = JSON.parse(staffCookie); isAuthValid = Date.now() <= userData.expiredAt; } catch (e) { isAuthValid = false; } } if (!isAuthValid) { const response = NextResponse.redirect(new URL(ROUTE_RULES.staff.loginPath, request.url)); response.cookies.delete(ROUTE_RULES.staff.cookieKey); return response; } } // 校验Client路由权限 if (ROUTE_RULES.client.protectedPaths.some(path => pathname.startsWith(path))) { const clientCookie = request.cookies.get(ROUTE_RULES.client.cookieKey)?.value; let isAuthValid = false; if (clientCookie) { try { const userData = JSON.parse(clientCookie); isAuthValid = Date.now() <= userData.expiredAt; } catch (e) { isAuthValid = false; } } if (!isAuthValid) { const response = NextResponse.redirect(new URL(ROUTE_RULES.client.loginPath, request.url)); response.cookies.delete(ROUTE_RULES.client.cookieKey); return response; } } // 已认证用户访问登录页时跳转至仪表盘 if (pathname === ROUTE_RULES.staff.loginPath) { const staffCookie = request.cookies.get(ROUTE_RULES.staff.cookieKey)?.value; if (staffCookie) { try { const userData = JSON.parse(staffCookie); if (Date.now() <= userData.expiredAt) { return NextResponse.redirect(new URL('/staff', request.url)); } } catch (e) {} } } if (pathname === ROUTE_RULES.client.loginPath) { const clientCookie = request.cookies.get(ROUTE_RULES.client.cookieKey)?.value; if (clientCookie) { try { const userData = JSON.parse(clientCookie); if (Date.now() <= userData.expiredAt) { return NextResponse.redirect(new URL('/client', request.url)); } } catch (e) {} } } return NextResponse.next(); } // 指定中间件生效的路由范围 export const config = { matcher: ['/staff/:path*', '/client/:path*', '/auth/staff', '/auth/client'] };
2. 移除客户端ProtectedRoutes组件
中间件会在页面渲染前完成拦截,完全不需要客户端组件做二次校验,直接去掉布局文件中的ProtectedRoutes包裹:
修改后的staff/layout.tsx:
'use client'; import StaffMenu from '@/app/components/dashboard/staff-menu'; export default function StaffLayout({ children }: { children: React.ReactNode }) { return ( <div className="min-h-full"> <StaffMenu /> <main> <div className="mx-auto max-w-7xl py-6 sm:px-6 lg:px-8"> {children} </div> </main> </div> ); }
client/layout.tsx做同样修改即可。
3. 清理冗余代码
- 删除
staff/middleware.ts和client/middleware.ts - 删除
lib/router/staff/ProtectedRoutes.tsx和lib/router/client/ProtectedRoutes.tsx
优化说明
- 中间件在边缘/服务器端执行,请求到达页面之前就完成重定向,彻底解决闪显问题
- 统一路由与Cookie规则,避免逻辑不一致导致的权限漏洞
- 移除客户端冗余校验,减少不必要的客户端渲染逻辑
内容的提问来源于stack exchange,提问作者reactcoder
相关产品推荐
相关产品推荐

