You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Next.js 14中间件重定向问题:用户登录成功后仍被转至/login

Next.js 14 中间件重定向问题解决方案

核心问题分析

你的代码存在两个关键问题:

  • 中间件中定义了isAuthenticated验证JWT的函数,但从未实际调用,即使token无效或篡改也能绕过校验;而登录后立即访问受保护路由被重定向,核心原因是中间件无法读取到sessionToken Cookie,大概率是登录接口设置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);

测试验证

  1. 登录成功后,在浏览器Application面板查看sessionToken是否存在且路径为/
  2. 立即点击Dashboard链接,检查中间件是否读取到token并允许访问
  3. 若仍有问题,查看控制台日志确认中间件执行情况

内容的提问来源于stack exchange,提问作者Anni

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 20:07:32