Next.js 14中间件重定向问题:用户登录成功后仍被转至/login
Next.js 14 中间件重定向问题解决方案
核心问题分析
你的代码存在两个关键问题:
- 中间件中定义了
isAuthenticated验证JWT的函数,但从未实际调用,即使token无效或篡改也能绕过校验;而登录后立即访问受保护路由被重定向,核心原因是中间件无法读取到sessionTokenCookie,大概率是登录接口设置Cookie的参数不规范,或是Next.js路由缓存导致中间件逻辑未重新执行 - 点击跳转时无/dashboard请求,说明中间件在路由跳转前直接触发了重定向,请求未进入页面阶段
具体修复步骤
1. 完善中间件身份验证逻辑
修改middleware.ts,拿到sessionToken后调用isAuthenticated验证有效性,同时规范Cookie操作:
import { jwtVerify } from "jose"; import { NextResponse, NextRequest } from "next/server"; export const config = { matcher: ["/login", "/logout", "/dashboard", "/chat", "/team"], }; const JWT_SECRET = "mysecret"; // 后续建议移至.env文件保障安全 const isAuthenticated = async (sessionToken: string) => { try { const userSession = await jwtVerify( sessionToken, new TextEncoder().encode(JWT_SECRET) ); return userSession; } catch (e) { return false; } }; export async function middleware(request: NextRequest) { try { const sessionToken = request.cookies.get("sessionToken")?.value || null; if (request.nextUrl.pathname === "/logout") { const response = NextResponse.redirect(new URL("/", request.url)); response.cookies.set({ name: "sessionToken", value: "", path: "/", maxAge: 0, httpOnly: true, // 防止XSS攻击 secure: process.env.NODE_ENV === "production", // 生产环境HTTPS下启用 sameSite: "strict" }); return response; } // 无token时重定向登录页 if (!sessionToken) { if (request.nextUrl.pathname === "/login") { return NextResponse.next(); } return NextResponse.redirect(new URL("/login", request.url)); } // 新增:验证token有效性 const validSession = await isAuthenticated(sessionToken); if (!validSession) { const response = NextResponse.redirect(new URL("/login", request.url)); response.cookies.delete("sessionToken"); return response; } return NextResponse.next(); } catch (e) { return NextResponse.redirect(new URL("/login", request.url)); } }
2. 规范登录接口的Cookie设置
确保登录成功后设置sessionToken时,参数与logout一致,尤其是path="/",否则Cookie仅在当前路径生效:
// 示例登录接口(app/api/login/route.ts) import { NextResponse } from "next/server"; import { SignJWT } from "jose"; export async function POST(request: Request) { // 账号密码验证逻辑... // 生成JWT const token = await new SignJWT({ userId: "xxx" }) .setProtectedHeader({ alg: "HS256" }) .setExpirationTime("24h") .sign(new TextEncoder().encode("mysecret")); // 设置Cookie const response = NextResponse.json({ success: true }); response.cookies.set({ name: "sessionToken", value: token, path: "/", // 根路径确保所有路由可读取 maxAge: 86400, // 24小时有效期 httpOnly: true, secure: process.env.NODE_ENV === "production", sameSite: "strict" }); return response; }
3. 处理路由缓存问题
Next.js 14 App Router默认缓存静态路由,可能导致中间件逻辑未及时执行,可通过以下方式解决:
- 在受保护页面添加
revalidate: 0禁用缓存:
// app/dashboard/page.tsx export const revalidate = 0; // 禁用缓存,每次请求触发中间件 export default function Dashboard() { return <div>Dashboard</div>; }
- 或在
Link组件添加reload属性强制刷新:
// Navbar组件中修改Dashboard链接 <Link href="/dashboard" className="hover:underline" reload> Dashboard </Link>
4. 同步客户端状态与服务器Cookie
Navbar依赖全局上下文session控制Logout显示,但客户端状态可能与服务器Cookie不同步,建议从Cookie同步状态:
// globalContext.tsx示例 "use client"; import { createContext, useContext, useEffect, useState } from "react"; const GlobalContext = createContext({ session: false, setSession: (value: boolean) => {} }); export function GlobalContextProvider({ children }: { children: React.ReactNode }) { const [session, setSession] = useState(false); useEffect(() => { // 从Cookie读取token同步状态 const sessionToken = document.cookie.split("; ").find(row => row.startsWith("sessionToken="))?.split("=")[1]; setSession(!!sessionToken); }, []); return ( <GlobalContext.Provider value={{ session, setSession }}> {children} </GlobalContext.Provider> ); } export const useGlobalContextProvider = () => useContext(GlobalContext);
测试验证
- 登录成功后,在浏览器Application面板查看
sessionToken是否存在且路径为/ - 立即点击Dashboard链接,检查中间件是否读取到token并允许访问
- 若仍有问题,查看控制台日志确认中间件执行情况
内容的提问来源于stack exchange,提问作者Anni
相关产品推荐
相关产品推荐

