Supabase Auth UI+Google登录无法触发AuthProvider,前端无会话问题排查
问题:Vite + React Router v6 + Supabase Google OAuth 认证后前端无法获取会话
我正在使用Vite + React Router v6 + Supabase Auth组件结合Google OAuth提供商,已完成以下配置:
- Supabase控制台添加了Google凭据
- Google客户端配置中设置了回调地址
https://{my_supabase_id}.supabase.co/auth/v1/callback - Google授权源和Supabase站点URL均配置为Vite本地地址
http://localhost:5173
目前Supabase认证表中能看到用户已完成认证,但前端AuthProvider里的会话创建调试断点从未触发,导致页面因检测不到会话而自动跳转到登录界面。
以下是我的相关代码:
AuthProvider 代码
const AuthProvider = (props: AuthProviderProps) => { const [user, setUser] = useState<User | null>(null); const [session, setSession] = useState<Session | null>(null); const [loading, setLoading] = useState<boolean>(true); useEffect(() => { const { data: listener } = supabase.auth.onAuthStateChange( (_event, session) => { console.log('session onAuthStateChange: ', session); if (session) { debugger; } setSession(session); setUser(session?.user || null); setLoading(false); } ); const setData = async () => { const { data: { session }, error, } = await supabase.auth.getSession(); console.log('session at setData:', session); if (session) { debugger; } if (error) { throw error; } setSession(session); setUser(session?.user || null); setLoading(false); }; setData(); return () => { listener?.subscription.unsubscribe(); }; }, [supabase.auth]); const value = { session, user, }; return ( <AuthContext.Provider value={value}>{props.children}</AuthContext.Provider> ); }; export const useAuth = () => { return useContext(AuthContext); }; export default AuthProvider;
路由配置代码
const router = createBrowserRouter([ { path: '/', element: ( <AuthProvider> <Root /> </AuthProvider> ), errorElement: <ErrorPage />, children: [ { path: 'login', element: <Login />, }, { path: '/', element: <ProtectedPage />, children: [ { path: 'picks', element: <Picks />, loader: picksLoader, }, ], }, ], }, ]); ReactDOM.createRoot(document.getElementById('root')!).render( <React.StrictMode> <RouterProvider router={router} /> </React.StrictMode> );
ProtectedPage 组件代码
const ProtectedPage = () => { const { user, session } = useAuth(); if (!session) { return <Navigate to='/login' replace />; } return <Layout />; };
Login 组件代码
export const Login = () => { return ( <div className='md:flex md:justify-center mb-6'> <div className='flex-col prose'> <h1>bp2</h1> <div className='items-center justify-center mx-12 h-screen'> <Auth supabaseClient={supabase} appearance={{ theme: ThemeSupa }} providers={['google']} /> </div> </div> </div> ); };
简单流程说明:访问根路径/时会加载<ProtectedPage>,如果检测不到session就跳转到登录页面;登录组件使用了@supabase/auth-ui-react的<Auth />组件实现Google登录。
我遗漏了什么配置或代码逻辑?
解决方案
1. 修复会话加载时的误跳转问题
你的ProtectedPage忽略了组件初始化阶段的loading状态——此时会话还未完成获取,就被误判为未登录并跳转。
首先更新AuthProvider的context值,把loading状态传递出去:
const value = { session, user, loading, // 新增这行 };
然后修改ProtectedPage,先等待会话加载完成:
const ProtectedPage = () => { const { user, session, loading } = useAuth(); if (loading) { return <div>加载中...</div>; // 可替换为骨架屏等自定义加载状态 } if (!session) { return <Navigate to='/login' replace />; } return <Layout />; };
2. 优化AuthProvider的状态更新逻辑
添加组件挂载状态标记,避免组件卸载后更新状态,同时处理重复设置loading的问题:
useEffect(() => { let isMounted = true; const { data: listener } = supabase.auth.onAuthStateChange( (_event, session) => { if (!isMounted) return; console.log('session onAuthStateChange: ', session); setSession(session); setUser(session?.user || null); setLoading(false); } ); const setData = async () => { const { data: { session }, error } = await supabase.auth.getSession(); if (!isMounted) return; console.log('session at setData:', session); if (error) { console.error('获取会话失败:', error); setLoading(false); return; } setSession(session); setUser(session?.user || null); setLoading(false); }; setData(); return () => { isMounted = false; listener?.subscription.unsubscribe(); }; }, [supabase.auth]);
3. 检查Supabase客户端初始化配置
确保客户端初始化时正确设置auth.redirectTo,指定为当前应用的地址:
const supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY, { auth: { redirectTo: window.location.origin, // 本地开发时会自动取http://localhost:5173 }, });
4. 处理React StrictMode的重复挂载影响
React StrictMode会触发组件两次挂载,可能干扰Supabase监听器。上面添加的isMounted标记已经处理了这个问题,若仍有异常可暂时关闭StrictMode测试。
内容的提问来源于stack exchange,提问作者AlxVallejo
相关产品推荐
相关产品推荐

