Vercel部署后Firebase Google Auth登出后currentUser始终为null
问题:Vercel部署后Google Auth仅首次正常工作,登出后currentUser始终为null
本地localhost环境下可多次重新登录,currentUser始终返回包含数据的对象,但部署到Vercel后,Google Auth仅首次登录正常,登出后再次登录时currentUser始终为null。
已尝试的解决方法
- 调整useEffect的依赖项
- 禁用Chrome的
chrome://flags/#third-party-storage-partitioning设置
相关代码
'use client' import { useEffect, useState, useContext, createContext } from 'react' import { useRouter } from 'next/navigation' import {getAuth, GoogleAuthProvider, onAuthStateChanged, signInWithRedirect} from 'firebase/auth' import { User } from 'firebase/auth' import '@/services/firebaseConfig' import { DocumentData, doc, getDoc } from 'firebase/firestore' import {auth, db} from '@/services/firebaseConfig' import { usePathname } from 'next/navigation' import {DEFAULT_REDIRECT_PATH} from "@/config/constants"; interface AuthProviderProps { children: React.ReactNode } interface AuthContextType { user: User | null authLoading: boolean userData: DocumentData | undefined setUser: (user: User | null) => void setUserData: (user: DocumentData | undefined) => void } const AuthContext = createContext<AuthContextType | null>(null) export const useAuth = () => { return useContext(AuthContext) } export const AuthProvider = ({ children }: AuthProviderProps) => { const router = useRouter() const [authLoading, setAuthLoading] = useState(false) const [user, setUser] = useState<User | null>(null) const [userData, setUserData] = useState<DocumentData | undefined>() const pathname = usePathname() useEffect(() => { const auth = getAuth() const unsubscribe = onAuthStateChanged(auth, (currentUser) => { if (currentUser) { const userRef = doc(db, 'users', currentUser.uid) // const userDoc = await getDoc(userRef) // setUser(currentUser) // setUserData(userDoc.data()) if (['/login', '/register'].includes(pathname || '')) { if(currentUser.emailVerified) { router.replace(DEFAULT_REDIRECT_PATH) } } } else { // setUser(null) // setUserData(undefined) } console.log('currentUser', currentUser) if ( !currentUser && !['/', '/register', '/legal', '/login'].includes(pathname || '') ) { router.replace('/login') } else { // setAuthLoading(false) } }) return () => unsubscribe() }, [user]) return ( <AuthContext.Provider value={{ user, authLoading, userData, setUser, setUserData }}> {children} </AuthContext.Provider> ) }
问题分析与解决建议
- 修正useEffect依赖项:当前useEffect依赖
user状态,但回调内未更新user(相关代码被注释),导致监听逻辑异常。应将依赖项改为pathname和router,或使用空数组(因为onAuthStateChanged是长期监听,无需频繁重新订阅)。 - 同步Context中的用户状态:取消注释回调里的
setUser(currentUser)和setUserData代码,确保Firebase认证状态变化时,Context中的user状态能同步更新,否则UI层无法获取最新认证信息。 - 检查Firebase跨域配置:在Firebase控制台中确认:
- 认证 > 设置 > 授权域已添加Vercel部署的域名
firebaseConfig中的authDomain与部署域名完全匹配
- 处理Next.js客户端缓存:作为客户端组件,可能存在缓存导致认证状态未刷新。可在相关页面添加
export const dynamic = 'force-dynamic'强制禁用静态缓存,或在登录/登出操作后调用revalidatePath刷新路由。 - 修复异步用户数据获取:若需从Firestore获取用户数据,需将回调改为
async函数,正确处理异步逻辑,示例调整如下:
useEffect(() => { const auth = getAuth() const unsubscribe = onAuthStateChanged(auth, async (currentUser) => { if (currentUser) { setUser(currentUser) const userRef = doc(db, 'users', currentUser.uid) const userDoc = await getDoc(userRef) setUserData(userDoc.data()) if (['/login', '/register'].includes(pathname || '')) { if(currentUser.emailVerified) { router.replace(DEFAULT_REDIRECT_PATH) } } } else { setUser(null) setUserData(undefined) } console.log('currentUser', currentUser) if ( !currentUser && !['/', '/register', '/legal', '/login'].includes(pathname || '') ) { router.replace('/login') } }) return () => unsubscribe() }, [pathname, router])
内容的提问来源于stack exchange,提问作者Александр Мерный
相关产品推荐
相关产品推荐

