Next.js App Router中如何在中间件访问sessionStorage实现鉴权
解决Next.js App Router中间件无法访问sessionStorage的路由保护问题
你猜的没错,sessionStorage是浏览器端的存储API,而Next.js的中间件运行在服务端/边缘环境,根本拿不到客户端的存储数据。要实现服务端层面的路由保护,必须把认证状态存在服务端可读取的位置,下面给两种实用方案:
方案一:自定义HttpOnly Cookie实现(轻量自主可控)
1. 登录时在服务端设置安全Cookie
放弃把用户数据存在sessionStorage,转而在登录校验通过后,用服务端逻辑设置HttpOnly类型的Cookie(这类Cookie客户端JS无法读取,更安全):
// app/api/login/route.js import { cookies } from 'next/headers'; export async function POST(request) { const { email, password } = await request.json(); // 这里替换成你的用户校验逻辑(比如查数据库) const user = await verifyUserCredentials(email, password); if (user) { // 设置带用户标识的Cookie cookies().set({ name: 'auth_session', value: JSON.stringify({ userId: user.id, email: user.email }), httpOnly: true, // 禁止客户端JS读取,防XSS secure: process.env.NODE_ENV === 'production', // 生产环境强制HTTPS sameSite: 'strict', maxAge: 60 * 60 * 24, // 有效期1天 path: '/', }); return Response.json({ success: true }); } return Response.json({ success: false }, { status: 401 }); }
2. 中间件读取Cookie做路由校验
在middleware.js里读取Cookie,判断用户是否有权限访问保护路由:
// middleware.js import { NextResponse } from 'next/server'; import type { NextRequest } from 'next/server'; export function middleware(request: NextRequest) { // 读取认证Cookie const authSession = request.cookies.get('auth_session')?.value; // 定义需要保护的路由列表 const protectedRoutes = ['/dashboard']; const isAccessingProtectedRoute = protectedRoutes.some(route => request.nextUrl.pathname.startsWith(route) ); // 未登录访问保护路由 → 重定向到登录页 if (isAccessingProtectedRoute && !authSession) { return NextResponse.redirect(new URL('/login', request.url)); } // 已登录访问登录页 → 重定向到仪表盘 if (request.nextUrl.pathname === '/login' && authSession) { return NextResponse.redirect(new URL('/dashboard', request.url)); } return NextResponse.next(); } // 指定中间件生效的路由范围 export const config = { matcher: ['/login', '/dashboard/:path*'], };
3. 客户端获取用户信息
在服务端组件里读取Cookie,把用户数据传给页面:
// app/dashboard/page.js import { cookies } from 'next/headers'; export default async function DashboardPage() { const authSession = cookies().get('auth_session')?.value; const user = authSession ? JSON.parse(authSession) : null; return ( <div> <h1>欢迎回来,{user?.email}</h1> {/* 仪表盘内容 */} </div> ); }
4. 登出逻辑
用Server Action清除Cookie:
// app/actions/authActions.js 'use server'; import { cookies } from 'next/headers'; export async function logout() { cookies().delete('auth_session'); }
方案二:用NextAuth.js(官方封装,省心省力)
如果不想自己写Cookie逻辑,直接用NextAuth.js,它封装了完整的认证流程,支持多种登录方式:
1. 安装依赖
npm install next-auth
2. 创建Auth配置文件
// app/api/auth/[...nextauth]/route.js import NextAuth from 'next-auth'; import CredentialsProvider from 'next-auth/providers/credentials'; const handler = NextAuth({ providers: [ CredentialsProvider({ name: '账号密码登录', credentials: { email: { label: '邮箱', type: 'email' }, password: { label: '密码', type: 'password' }, }, async authorize(credentials) { // 替换成你的用户校验逻辑 const user = await verifyUserCredentials(credentials.email, credentials.password); return user ? user : null; }, }), ], session: { strategy: 'jwt' }, pages: { signIn: '/login' }, // 指定自定义登录页路径 }); export { handler as GET, handler as POST };
3. 中间件里用NextAuth做校验
// middleware.js import { getServerSession } from 'next-auth/next'; import { NextResponse } from 'next/server'; import { authOptions } from './app/api/auth/[...nextauth]/route'; export async function middleware(request) { const session = await getServerSession(authOptions); const protectedRoutes = ['/dashboard']; const isAccessingProtectedRoute = protectedRoutes.some(route => request.nextUrl.pathname.startsWith(route) ); if (isAccessingProtectedRoute && !session) { return NextResponse.redirect(new URL('/login', request.url)); } if (request.nextUrl.pathname === '/login' && session) { return NextResponse.redirect(new URL('/dashboard', request.url)); } return NextResponse.next(); } export const config = { matcher: ['/login', '/dashboard/:path*'], };
4. 客户端获取用户信息
用useSession钩子(仅限客户端组件):
// app/dashboard/page.js 'use client'; import { useSession } from 'next-auth/react'; export default function DashboardPage() { const { data: session } = useSession(); if (!session) return <div>请先登录</div>; return ( <div> <h1>欢迎回来,{session.user.email}</h1> </div> ); }
核心总结
服务端中间件无法读取客户端存储,必须将认证状态放在服务端可访问的介质(比如Cookie)里,才能实现可靠的路由拦截。如果追求快速开发,优先选NextAuth.js;如果需要高度自定义,就用HttpOnly Cookie方案。
内容的提问来源于stack exchange,提问作者AmirHossein
相关产品推荐
相关产品推荐

