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

Next.js中间件用jose验证Access Token时陷入无限循环无法跳转登录页

Next.js中间件验证JWT陷入无限循环的问题解决

我在Next.js中间件中使用jose库验证Access Token时,遇到了一个问题:当代码进入catch块(比如Token无效或被篡改时),会陷入无限循环,无法正常跳转到登录页。尤其在用户修改浏览器中的Access Token时,这个问题特别明显。

我的代码如下:

import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";
import { jwtVerify } from 'jose';

export default async function middleware(request: NextRequest) {
    const access = request.cookies.get("access")?.value;
    const url = request.url;
    const urlStartWithUrl = `${process.env.NEXT_PUBLIC_HOST_FRONTEND}/open-bo-account`;
    const redirectUrl = `${process.env.NEXT_PUBLIC_HOST_FRONTEND}/login/`;


    if (!access && request.nextUrl.pathname.startsWith('/open-bo-account')) {
        request.cookies.clear()
        return NextResponse.redirect(new URL('/login', request.url));

    } else if (access) {
        try {
            const secret = new TextEncoder().encode(
                "secret key"
            );
            const decodedToken = await jwtVerify(access, secret);
            if (decodedToken) {
                return NextResponse.next();
            }
            request.cookies.clear();
            return NextResponse.redirect(new URL('/login', request.url));
        } catch (error) {
            const cookiesBeforeClear = request.cookies.getAll();
            console.log("Cookies before clear:", cookiesBeforeClear);
            request.cookies.clear();
            const cookiesAfterClear = request.cookies.getAll();
            console.log("Cookies after clear:", cookiesAfterClear);
            return NextResponse.redirect(new URL('/login', request.url));
        }
    }
}

问题原因

  • 错误的cookie清除方式:request.cookies.clear()只是修改了请求对象中的临时cookie数据,并不会向浏览器发送清除cookie的响应头。这导致浏览器中的access cookie始终存在,每次重定向后中间件都会读取到无效Token,重复进入catch块触发循环。
  • 未排除登录页路由:中间件默认拦截所有路由请求,包括重定向后的/login页面。即使cookie被正确清除,原逻辑也未对登录页做放行处理,进一步加剧循环风险。

解决方案

  1. 正确清除浏览器cookie:通过NextResponse对象的cookie方法设置过期或直接删除,让浏览器真正移除无效cookie。
  2. 排除登录页路由:在中间件开头判断如果是登录页请求,直接放行,避免拦截重定向后的请求。
  3. 优化路由保护逻辑:仅对需要验证的路由(如/open-bo-account)执行Token验证,减少不必要的处理。

修改后的代码:

import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";
import { jwtVerify } from 'jose';

export default async function middleware(request: NextRequest) {
    // 排除登录页,直接放行
    if (request.nextUrl.pathname.startsWith('/login')) {
        return NextResponse.next();
    }

    const access = request.cookies.get("access")?.value;
    const protectedPath = '/open-bo-account';

    // 仅处理需要保护的路由
    if (request.nextUrl.pathname.startsWith(protectedPath)) {
        if (!access) {
            // 清除所有cookie并跳转到登录页
            const response = NextResponse.redirect(new URL('/login', request.url));
            response.cookies.clear();
            return response;
        }

        try {
            // 建议将密钥放在环境变量中,不要硬编码
            const secret = new TextEncoder().encode(process.env.JWT_SECRET || "secret key");
            await jwtVerify(access, secret);
            // Token验证通过,放行
            return NextResponse.next();
        } catch (error) {
            console.error("Token验证失败:", error);
            // 清除无效的access cookie并跳转到登录页
            const response = NextResponse.redirect(new URL('/login', request.url));
            response.cookies.delete("access");
            // 如有refresh token也可一并删除
            // response.cookies.delete("refresh");
            return response;
        }
    }

    // 其他路由直接放行
    return NextResponse.next();
}

补充说明

  • 务必将JWT密钥存入环境变量(如JWT_SECRET),避免硬编码泄露风险。
  • 使用response.cookies.delete("access")精准清除单个cookie,比clear()更灵活,适合只需要移除无效Token的场景。
  • 先排除登录页的逻辑,确保重定向后不会被中间件再次拦截,彻底切断循环链路。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 12:37:47