Skip to content

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 模式(仅客户端) ​

typescript
import { createClient } from '@supabase/supabase-js';
export const supabase = createClient(URL, ANON_KEY);

Next.js 模式(服务端-客户端同步) ​

在 Next.js 中应使用 @supabase/ssr,分别为服务端组件和客户端组件定义客户端。关键差异在于 Cookie Store。

typescript
// 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 中,使用中间件在会话无效时直接阻止页面渲染:

typescript
// 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 核心实现 ​

typescript
// auth.ts
import NextAuth from "next-auth";
import GitHub from "next-auth/providers/github";

export const { handlers, auth, signIn, signOut } = NextAuth({
  providers: [GitHub],
});

在组件中,可以这样检查会话:

typescript
// 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,目标都是利用服务端实现更好的安全性和更快的感知性能。

原文链接 ​

https://dev.to/digitaldev/migrating-auth-from-vite-to-nextjs-supabase-clerk-and-authjs-patterns-that-actually-work-2f46