How to Migrate from Supabase Auth Helpers to SSR package
auth-helpers 包已被弃用,取而代之的是 @supabase/ssr 包。我们建议迁移到 @supabase/ssr 包,因为未来的错误修复和功能更新将主要集中在 @supabase/ssr 包上。
🌐 The auth-helpers packages are deprecated and replaced with the @supabase/ssr package. We recommend migrating to the @supabase/ssr package as future bug fixes and feature releases are focused on the @supabase/ssr package.
这里有一些步骤,帮助你把应用从 auth-helpers 包迁移到 @supabase/ssr 包。
🌐 Here are the steps for you to migrate your application from the auth-helpers package to @supabase/ssr package.
根据你的实现,你可以忽略这部分文档并使用你自己的实现(比如用 API 路由而不是服务器操作)。重要的是,你要用 @supabase/ssr 提供的客户端创建的工具函数替换掉 auth-helpers 提供的客户端。
🌐 Depending on your implementation, you may ignore some parts of this documentation and use your own implementation (i.e. using API routes vs. Server Actions). What's important is you replace the clients provided by auth-helpers with the utility functions created using clients provided by @supabase/ssr.
1. 卸载 Supabase Auth 辅助工具,然后安装 Supabase SSR 包 #
🌐 1. Uninstall Supabase Auth helpers and install the Supabase SSR package
重要的是,你不要在同一个应用里同时使用 auth-helpers-nextjs 和 @supabase/ssr 包,以免遇到认证问题。
🌐 It's important that you don't use both auth-helpers-nextjs and @supabase/ssr packages in the same application to avoid running into authentication issues.
1npm uninstall @supabase/auth-helpers-nextjs @supabase/supabase-js2npm install @supabase/ssr @supabase/supabase-js2. 创建用于生成 Supabase 客户端的库函数 #
🌐 2. Create the library functions to create Supabase clients
1// lib/supabase/client.ts23import { createBrowserClient } from '@supabase/ssr';45export function createClient() {6 return createBrowserClient(7 process.env.NEXT_PUBLIC_SUPABASE_URL!,8 process.env.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY!9 );10}1112// lib/supabase/server.ts13import { createServerClient } from '@supabase/ssr'14import { cookies } from 'next/headers'1516export async function createClient() {17 const cookieStore = await cookies()1819 return createServerClient(20 process.env.NEXT_PUBLIC_SUPABASE_URL!,21 process.env.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY!,22 {23 cookies: {24 getAll() {25 return cookieStore.getAll()26 },27 setAll(cookiesToSet, _headers) {28 try {29 cookiesToSet.forEach(({ name, value, options }) => cookieStore.set(name, value, options))30 } catch {31 // The `setAll` method was called from a Server Component.32 // This can be ignored if you have middleware refreshing33 // user sessions.34 }35 },36 },37 }38 )39}4041// lib/supabase/proxy.ts42import { createServerClient } from '@supabase/ssr'43import { NextResponse, type NextRequest } from 'next/server'4445export async function updateSession(request: NextRequest) {46 let supabaseResponse = NextResponse.next({47 request,48 })4950 // With Fluid compute, don't put this client in a global environment51 // variable. Always create a new one on each request.52 const supabase = createServerClient(53 process.env.NEXT_PUBLIC_SUPABASE_URL!,54 process.env.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY!,55 {56 cookies: {57 getAll() {58 return request.cookies.getAll()59 },60 setAll(cookiesToSet, headers) {61 cookiesToSet.forEach(({ name, value }) => request.cookies.set(name, value))62 supabaseResponse = NextResponse.next({63 request,64 })65 cookiesToSet.forEach(({ name, value, options }) => supabaseResponse.cookies.set(name, value, options))66 Object.entries(headers).forEach(([key, value]) =>67 supabaseResponse.headers.set(key, value)68 )69 },70 },71 }72 )7374 // Do not run code between createServerClient and75 // supabase.auth.getClaims(). A basic mistake could make it very hard to debug76 // issues with users being randomly logged out.7778 // IMPORTANT: If you remove getClaims() and you use server-side rendering79 // with the Supabase client, your users may be randomly logged out.80 const { data } = await supabase.auth.getClaims()8182 const user = data?.claims8384 if (85 !user &&86 !request.nextUrl.pathname.startsWith('/login') &&87 !request.nextUrl.pathname.startsWith('/auth')88 ) {89 // no user, potentially respond by redirecting the user to the login page90 const url = request.nextUrl.clone()91 url.pathname = '/login'92 return NextResponse.redirect(url)93 }9495 // IMPORTANT: You *must* return the supabaseResponse object as it is. If you're96 // creating a new response object with NextResponse.next() make sure to:97 // 1. Pass the request in it, like so:98 // const myNewResponse = NextResponse.next({ request })99 // 2. Copy over the cookies, like so:100 // myNewResponse.cookies.setAll(supabaseResponse.cookies.getAll())101 // 3. Change the myNewResponse object to fit your needs, but avoid changing102 // the cookies!103 // 4. Finally:104 // return myNewResponse105 // If this is not done, you may be causing the browser and server to go out106 // of sync and terminate the user's session prematurely!107108 return supabaseResponse109}3. 替换你的 proxy.ts 文件 #
🌐 3. Replace your proxy.ts file
1// proxy.ts23import { type NextRequest } from "next/server"4import { updateSession } from "@/lib/supabase/proxy"56export async function proxy(request: NextRequest) {7 return await updateSession(request)8}910export const config = {11 matcher: [12 /*13 * Match all request paths except for the ones starting with:14 * - _next/static (static files)15 * - _next/image (image optimization files)16 * - favicon.ico (favicon file)17 * Feel free to modify this pattern to include more paths.18 */19 "/((?!_next/static|_next/image|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)",20 ],21}4. 创建你的服务器操作来处理登录和注册 #
🌐 4. Create your server actions to handle login and sign up
1// app/login/actions.ts23'use server';45import { revalidatePath } from 'next/cache';6import { redirect } from 'next/navigation';78import { createClient } from '@/lib/supabase/server';910export async function login(formData: FormData) {11 const supabase = createClient();1213 // type-casting here for convenience14 // in practice, you should validate your inputs15 const data = {16 email: formData.get('email') as string,17 password: formData.get('password') as string,18 };1920 const { error } = await supabase.auth.signInWithPassword(data)2122 if (error) {23 redirect('/error');24 }2526 revalidatePath('/', 'layout');27 redirect('/');28}2930export async function signup(formData: FormData) {31 const supabase = createClient();3233 // type-casting here for convenience34 // in practice, you should validate your inputs35 const data = {36 email: formData.get('email') as string,37 password: formData.get('password') as string,38 };3940 const { error } = await supabase.auth.signUp(data);4142 if (error) {43 redirect('/error');44 }4546 revalidatePath('/', 'layout');47 redirect('/');48}5. 在你的登录页面界面中使用服务器操作 #
🌐 5. Use the server actions in your login page UI
1// app/login/page.tsx23import { login, signup } from './actions';45export default function LoginPage() {6 return (7 <form>8 <label htmlFor="email">Email:</label>9 <input id="email" name="email" type="email" required />10 <label htmlFor="password">Password:</label>11 <input id="password" name="password" type="password" required />12 <button formAction={login}>Log in</button>13 <button formAction={signup}>Sign up</button>14 </form>15 );16}6. 客户端组件 #
🌐 6. Client components
1'use client';23// replace this line4import { createClientComponentClient } from '@supabase/auth-helpers-nextjs';56// with7import { createClient } from '@/lib/supabase/client';89export default async function Page() {10 // replace this line11 const supabase = createClientComponentClient<Database>();1213 // with14 const supabase = createClient();1516 return...17}7. 服务器组件 #
🌐 7. Server components
1// replace2import { cookies } from 'next/headers';3import { createServerComponentClient } from '@supabase/auth-helpers-nextjs';45// with6import { createClient } from '@/lib/supabase/server';78export default async function Page() {9 // replace10 const cookieStore = cookies();11 const supabase = createServerComponentClient<Database>({12 cookies: () => cookieStore13 });1415 // with16 const supabase = createClient();1718 return...19}8. 路由处理器 #
🌐 8. Route handlers
1// replace2import { createRouteHandlerClient } from '@supabase/auth-helpers-nextjs';3import { cookies } from 'next/headers';45// with6import { createClient } from '@/lib/supabase/server';78export async function POST(request: Request) {9 // replace10 const supabase = createRouteHandlerClient<Database>({11 cookies: () => cookieStore,12 });1314 // with15 const supabase = createClient();1617 return...18}同样,你可以用你用 @supabase/ssr 创建的实用函数替换掉用 @supabase/auth-helpers-nextjs 创建的客户端。
🌐 Likewise, you can replace the clients created with @supabase/auth-helpers-nextjs with utility functions you created with @supabase/ssr.
createMiddlewareClient → createServerClient
createClientComponentClient → createBrowserClient
createServerComponentClient → createServerClient
createRouteHandlerClient → createServerClient
你可以在我们的 SSR 文档中找到更清晰简洁的创建客户端示例 在这里。
🌐 You can find more clear and concise examples of creating clients in our SSR documentation.
如果你对本指南有任何反馈,请在下面以评论的形式提供。如果你发现任何问题或对 @supabase/ssr 客户端有反馈,请在 @supabase/ssr 仓库中提交问题。
🌐 If you have any feedback about this guide, provide them as a comment below. If you find any issues or have feedback for the @supabase/ssr client, post them as an issue in @supabase/ssr repo.
像往常一样,我们的 GitHub 社区和 Discord 通道都开放,用于技术讨论和解决你的问题。
🌐 As always, our GitHub community and Discord channel are open for technical discussions and resolving your issues.