You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Pages目录搭建Supabase Auth + Next.js遇到的问题

解决方案:Next.js Pages 目录集成 Supabase Auth 并保留 _app.tsx

1. 修复 _app.tsx 的 Supabase 状态配置

问题核心是 _app.tsx 中 Supabase 客户端初始化或状态同步逻辑冲突,导致 Auth 状态异常。按以下方式配置全局 Provider:

import { createContext, useContext, useEffect, useState } from 'react'
import { Session, createClientComponentClient } from '@supabase/auth-helpers-nextjs'
import type { AppProps } from 'next/app'

const SupabaseContext = createContext<{
  supabase: ReturnType<typeof createClientComponentClient>
  session: Session | null
} | null>(null)

export const useSupabase = () => {
  const context = useContext(SupabaseContext)
  if (!context) throw new Error('useSupabase 必须在 SupabaseProvider 内部使用')
  return context
}

export default function App({ Component, pageProps }: AppProps<{ session: Session }>) {
  const supabase = createClientComponentClient()
  const [session, setSession] = useState<Session | null>(pageProps.session)

  useEffect(() => {
    const { data: { subscription } } = supabase.auth.onAuthStateChange((_event, session) => {
      setSession(session)
    })
    return () => subscription.unsubscribe()
  }, [supabase])

  return (
    <SupabaseContext.Provider value={{ supabase, session }}>
      <Component {...pageProps} />
    </SupabaseContext.Provider>
  )
}

2. 实现邮箱/密码 + OAuth 登录页面

基于 @supabase/auth-ui-react 快速构建登录界面,直接复用全局 Supabase 实例:

import { Auth } from '@supabase/auth-ui-react'
import { ThemeSupa } from '@supabase/auth-ui-shared'
import { useSupabase } from '../_app'

export default function LoginPage() {
  const { supabase } = useSupabase()

  return (
    <div style={{ maxWidth: '400px', margin: '2rem auto' }}>
      <Auth
        supabaseClient={supabase}
        appearance={{ theme: ThemeSupa }}
        providers={['google', 'github']} // 按需添加OAuth服务商
        redirectTo="/dashboard"
        signUp={true}
      />
    </div>
  )
}

3. 配置 Middleware 保护页面

通过 middleware.ts 拦截未认证用户访问受保护路由:

import { createMiddlewareClient } from '@supabase/auth-helpers-nextjs'
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

export async function middleware(req: NextRequest) {
  const res = NextResponse.next()
  const supabase = createMiddlewareClient({ req, res })

  const { data: { session } } = await supabase.auth.getSession()

  // 未登录访问受保护路由时重定向到登录页
  if (!session && req.nextUrl.pathname.startsWith('/dashboard')) {
    return NextResponse.redirect(new URL('/login', req.url))
  }

  return res
}

// 指定需要保护的路由规则
export const config = {
  matcher: ['/dashboard/:path*'],
}

4. 同步服务端与客户端状态

在受保护页面中通过 getServerSideProps 传递 session,避免状态不一致:

import { createServerComponentClient } from '@supabase/auth-helpers-nextjs'
import { cookies } from 'next/headers'
import type { GetServerSidePropsContext } from 'next'
import { useSupabase } from '../_app'

export default function DashboardPage() {
  const { session } = useSupabase()
  return <div>欢迎,{session?.user.email}</div>
}

export async function getServerSideProps(context: GetServerSidePropsContext) {
  const supabase = createServerComponentClient({ cookies: () => context.req.cookies })
  const { data: { session } } = await supabase.auth.getSession()

  if (!session) {
    return {
      redirect: {
        destination: '/login',
        permanent: false,
      },
    }
  }

  return {
    props: { session },
  }
}

关键注意事项

  • 全局仅保留一个 Supabase 客户端实例,避免重复初始化
  • 区分环境使用对应客户端:Middleware 用 createMiddlewareClient,客户端组件用 createClientComponentClient,服务端组件用 createServerComponentClient
  • 确保 @supabase/auth-helpers-nextjs 与 Next.js 版本兼容(推荐使用最新稳定版)

内容的提问来源于stack exchange,提问作者user20951184

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 07:22:45