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

Next.js 13集成Firebase Auth登出后无法自动跳转问题求助

Next.js 13 Firebase Auth登出后无法自动跳转的解决方案

核心问题分析

你遇到的问题本质是Next.js 13 App Router的组件渲染模型与Firebase Auth状态监听的兼容性问题:

  • 若ProtectedRoute或页面是服务器组件,无法监听客户端的Auth状态变化;
  • 上下文状态更新后,组件未重新触发路由判断;
  • 路由跳转方式不符合App Router的要求。

解决方案步骤

1. 修正Auth上下文的客户端组件属性与状态同步

首先确保useAuth.tsx是客户端组件,且状态订阅逻辑正确:

// src/context/useAuth.tsx
'use client' // 必须添加,确保是客户端组件

import { createContext, useContext, useEffect, useState } from 'react'
import { getAuth, onAuthStateChanged, signOut, User } from 'firebase/auth'
import { app } from '../firebase/config' // 你的Firebase初始化文件

const AuthContext = createContext<{
  user: User | null
  loading: boolean
  signOut: () => Promise<void>
}>({
  user: null,
  loading: true,
  signOut: async () => {}
})

export const AuthProvider = ({ children }: { children: React.ReactNode }) => {
  const [user, setUser] = useState<User | null>(null)
  const [loading, setLoading] = useState(true)
  const auth = getAuth(app)

  useEffect(() => {
    // 订阅Auth状态变化,注意清理订阅
    const unsubscribe = onAuthStateChanged(auth, (currentUser) => {
      setUser(currentUser)
      setLoading(false)
    })

    return () => unsubscribe()
  }, [auth])

  const handleSignOut = async () => {
    await signOut(auth)
  }

  return (
    <AuthContext.Provider value={{ user, loading, signOut: handleSignOut }}>
      {children}
    </AuthContext.Provider>
  )
}

export const useAuth = () => useContext(AuthContext)

2. 重写ProtectedRoute为客户端组件适配App Router

App Router中不建议用传统HOC做路由守卫,改用客户端组件包裹的方式,确保能监听Auth状态变化:

// src/hoc/ProtectedRoute.tsx
'use client'

import { useAuth } from '../context/useAuth'
import { useRouter } from 'next/navigation'
import { useEffect } from 'react'

export const ProtectedRoute = ({ children }: { children: React.ReactNode }) => {
  const { user, loading } = useAuth()
  const router = useRouter()

  useEffect(() => {
    // 等待加载完成后判断用户状态
    if (!loading && !user) {
      router.replace('/signin') // 用replace避免回退到原页面
    }
  }, [user, loading, router])

  // 加载中显示占位符
  if (loading) {
    return <div>加载中...</div>
  }

  // 未登录且加载完成时不渲染子组件
  if (!user) {
    return null
  }

  return <>{children}</>
}

然后在(main)/layout.tsx中使用这个守卫:

// src/app/(main)/layout.tsx
import { ProtectedRoute } from '../../hoc/ProtectedRoute'

export default function MainLayout({ children }: { children: React.ReactNode }) {
  return (
    <ProtectedRoute>
      {/* 你的主布局内容 */}
      {children}
    </ProtectedRoute>
  )
}

3. 推荐:使用Next.js Middleware做全局路由拦截(更可靠)

客户端组件守卫可能存在状态滞后问题,用Middleware能在请求到达页面之前处理,彻底解决状态不同步:

// src/middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
import { getAuth } from 'firebase/auth'
import { app } from './firebase/config'

export async function middleware(request: NextRequest) {
  const auth = getAuth(app)
  // 获取当前用户(需确保Firebase Auth与Next.js会话同步)
  const user = await new Promise((resolve) => {
    const unsubscribe = auth.onAuthStateChanged((user) => {
      resolve(user)
      unsubscribe()
    })
  })

  // 定义需要保护的路由
  const protectedRoutes = ['/home', '/plans', '/profile']
  const isProtectedRoute = protectedRoutes.some(route => request.nextUrl.pathname.startsWith(route))

  // 未登录且访问受保护路由,重定向到登录页
  if (isProtectedRoute && !user) {
    return NextResponse.redirect(new URL('/signin', request.url))
  }

  // 已登录且访问/auth路由,重定向到主页
  const authRoutes = ['/signin', '/signup']
  const isAuthRoute = authRoutes.some(route => request.nextUrl.pathname.startsWith(route))
  if (isAuthRoute && user) {
    return NextResponse.redirect(new URL('/home', request.url))
  }

  return NextResponse.next()
}

// 指定Middleware生效的路由
export const config = {
  matcher: ['/home/:path*', '/plans/:path*', '/profile/:path*', '/signin', '/signup']
}

关键注意事项

  • 所有涉及Auth状态监听和路由跳转的组件必须添加'use client'指令;
  • 避免在服务器组件中直接访问Auth状态,否则无法实时响应变化;
  • Middleware中获取Firebase用户时,需确保Firebase初始化代码是可在边缘环境运行的(避免使用浏览器专属API)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 04:17:22