Next生产环境middleware.ts拦截失效
2024-08 1
在next的middleware.ts
中,判断当前用户是否有权限进入指定页面时,比如/middleware/home
页面,用的是next-auth/jwt
中的getToken
,现在遇到一种情况,明明获取的token
是null了,但是还是渲染没权限的页面,具体代码如下:
import { getToken } from "next-auth/jwt";
import { type NextRequest, NextResponse } from "next/server";
import { PATHS } from "@/constants";
export async function middleware(req: NextRequest) {
const secret = process.env.AUTH_SECRET;
try {
// 确保环境变量已定义
if (!secret) {
throw new Error("AUTH_SECRET is not defined");
}
const token = await getToken({
req,
secret,
salt:
process.env.NODE_ENV === "production"
? "__Secure-authjs.session-token"
: "authjs.session-token",
cookieName:
process.env.NODE_ENV === "production"
? "__Secure-authjs.session-token"
: "authjs.session-token",
});
const { pathname } = req.nextUrl;
const redirectAuthSignUrl = new URL(PATHS.AUTH_SIGN_IN, req.url);
if (!token) {
return NextResponse.redirect(redirectAuthSignUrl, { status: 302 });
}
// 只有管理员才能访问 /admin 路径
if (pathname.startsWith(PATHS.ADMIN_HOME) && token.role !== "admin") {
return NextResponse.redirect(new URL("/403", req.url));
}
// 放行其他请求
return NextResponse.next();
} catch (e) {
console.log("middleware报错", e);
console.log("middleware process.env", process.env);
}
}
export const config = {
matcher: ["/middleware/:path*"],
};
后来经过一步步排查,发现在请求该页面的时候,根本没有走middleware.ts
的逻辑,而是直接请求该页面的资源,请求结束后才触发middleware.ts
的逻辑,但此时页面已经不会跳转。
之后一直卡在为什么该页面不会走middleware.ts
的逻辑这一步,多次google之后,了解到不是所有页面都会经过middleware.ts
的逻辑的,Next
在执行中间件得到时候,有自己的一套逻辑,对于静态页面,会直接返回,对于动态页面,才会走中间件的逻辑。
此时再回去排查该页面的代码,发现该页面的代码非常简单,如下所示:
import React from "react";
export default function AdminHomePage() {
return <span>hello world</span>;
}
由于代码非常简单,且没有后端交互,这就导致当前路由的页面被Next解析为静态页面,从而避开了中间件的逻辑,因此,也就导致即使是中间件里getToken为null了,该页面也不会进行跳转。
修复的逻辑非常简单,将给页面强制为服务端渲染即可:
import React from "react";
export const dynamic = "force-dynamic";
export default function AdminHomePage() {
return <span>hello world</span>;
}
上述代码中,加了一行export const dynamic = "force-dynamic";
,这一行代码告诉Next,当前页面需要动态渲染,动态渲染的页面必定会经过中间件的逻辑。
目录
- 无目录
- Next