Vite 迁移 Next.js:Supabase、Clerk 与 Auth.js 认证模式实战
译注:本文翻译自 dev.to 技术博客,原文作者 digitaldev,发布时间为 2026 年 9 月 16 日。原文链接:Migrating Auth from Vite to Next.js: Supabase, Clerk, and Auth.js Patterns That Actually Work。文中观点与代码示例均来自原文,供开发者参考。
架构转变:客户端认证 vs 服务端认证
使用 Vite 构建标准 React 应用时,认证逻辑通常完全运行在浏览器端:一个 useAuth Hook、一个 Context Provider,JWT 令牌存放在 localStorage 或 sessionStorage 中。
迁移到 Next.js 后,情况发生变化。你不再只管理客户端状态,而是要在客户端、服务端(SSR)和中间件之间管理会话。如果迁移时不调整认证模式,就会出现"闪烁"UI——受保护内容短暂显示后,客户端脚本才发现用户已登出。
本文介绍如何将三种主流认证模式从 Vite 迁移到 Next.js App Router。
一、Supabase:从 supabase-js 转向 SSR Helpers
在 Vite 应用中,通常只初始化一次 Supabase 客户端并导出。而在 Next.js 中,需要动态创建客户端,以便在服务端和客户端之间正确处理 Cookie。
Vite 模式(仅客户端)
import { createClient } from '@supabase/supabase-js';
export const supabase = createClient(URL, ANON_KEY);Next.js 模式(服务端-客户端同步)
在 Next.js 中应使用 @supabase/ssr,分别为服务端组件和客户端组件定义客户端。关键差异在于 Cookie Store。
// lib/supabase/server.ts
import { createServerClient } from '@supabase/ssr';
import { cookies } from 'next/headers';
export function createClient() {
const cookieStore = cookies();
return createServerClient(process.env.SUPABASE_URL!, process.env.SUPABASE_ANON_KEY!, {
cookies: {
getAll() { return cookieStore.getAll() },
setAll(cookiesToSet) {
cookiesToSet.forEach(({ name, value, options }) => cookieStore.set(name, value, options))
},
},
});
}将认证迁移到服务端后,可以直接在页面组件中执行数据库查询,无需内部 API 路由。
二、Clerk:无缝过渡
Clerk 可以说是最容易迁移的方案,因为其 SDK 在设计时就考虑了 Next.js。在 Vite 应用中,你用 <ClerkProvider> 包裹应用;在 Next.js 中,同样在 layout.tsx 中包裹,同时还能通过 middleware.ts 获得边缘级保护。
路由保护
在 Vite 中,你可能使用 <ProtectedRoute> 组件检查 user.isLoading。在 Next.js 中,使用中间件在会话无效时直接阻止页面渲染:
// middleware.ts
import { clerkMiddleware, createRouteMatcher } from "@clerk/nextjs/server";
const isPublicRoute = createRouteMatcher(['/sign-in(.*)', '/sign-up(.*)', '/']);
export default clerkMiddleware((auth, request) => {
if (!isPublicRoute(request)) {
auth().protect();
}
});三、Auth.js(NextAuth):自定义后端标准方案
如果你在 Vite 中使用自定义 JWT 实现(例如手动将令牌存入 Cookie),应迁移到 Auth.js。它处理了 OIDC、OAuth 和数据库会话的繁重工作。
手动重写这些模式是理解 App Router 细节的好方法,但希望加速迁移的开发者可以借助 ViteToNext.AI 自动重构项目文件和组件逻辑,以适配 Next.js 环境。
Auth.js 核心实现
// auth.ts
import NextAuth from "next-auth";
import GitHub from "next-auth/providers/github";
export const { handlers, auth, signIn, signOut } = NextAuth({
providers: [GitHub],
});在组件中,可以这样检查会话:
// Page.tsx (Server Component)
import { auth } from "./auth";
export default async function Page() {
const session = await auth();
if (!session) return <div>Please log in</div>;
return <div>Welcome {session.user?.name}</div>;
}处理受保护路由的重定向
迁移中一个常见陷阱是使用 window.location 进行重定向。在 Next.js 中,应使用 next/navigation 的 redirect() 函数:
- 服务端组件: 使用
redirect('/login')。 - 客户端组件: 使用
useRouter()和router.push('/login')。 - 中间件: 返回
NextResponse.redirect()。
结语
从 Vite 迁移认证到 Next.js,不只是移动代码,更是思维方式的转变——从"页面加载后获取数据"转向"页面渲染前验证用户"。无论选择 Supabase、Clerk 还是 Auth.js,目标都是利用服务端实现更好的安全性和更快的感知性能。