在 Proxy(原 Middleware) 实现 身份验证
在 Next.js 16 中,推荐使用 proxy(原 middleware) 来统一处理登录态校验与访问控制。由于所有请求都会经过这一层,非常适合做集中式鉴权与重定向。
1. 核心思路
- 放行公共资源, 例如:登录页(/login), 首页(/), 这些页面无需登录即可访问,应直接放行。
- 乐观检查(Optimistic Check), 优先检查 Cookie 中是否存在登录凭证:sb-access-token, sb-refresh-token
- 服务端验证用户状态
- 放行API请求和静态资源
2. 示例实现
// proxy.ts
import { NextRequest, NextResponse } from "next/server";
import { createSupabaseServerClient } from "./lib/supabase/server";
// 指定公开路由和保护的路由
const publicRoutes = ["/login", "/courses", "/"];
export default async function proxy(req: NextRequest) {
// 检查路由是否是公开
const path = req.nextUrl.pathname;
const isPublicRoute = publicRoutes.includes(path);
if (isPublicRoute) {
return NextResponse.next();
}
// 先做“乐观检查”(是否有 token)
const hasAuthCookie = req.cookies
.getAll()
.some((cookie) => cookie.name.startsWith("sb-") && cookie.name.endsWith("-auth-token"));
if (!hasAuthCookie) {
return NextResponse.redirect(new URL("/login", req.url));
}
// 检查用户状态
const {
data: { user },
} = await (await createSupabaseServerClient()).auth.getUser();
// 未授权用户重定向
if (!user) {
return NextResponse.redirect(new URL("/login", req.nextUrl));
}
return NextResponse.next();
}
// Routes Proxy should not run on
export const config = {
matcher: ["/((?!api|_next/static|_next/image|favicon.ico|.*\\.png$).*)"],
};