Google OAuth登录后Supabase无法获取已登录用户问题
问题分析
这个问题的核心是OAuth重定向回调完成后,服务器端的Supabase Auth会话还未完全初始化,导致首次访问/complete_profile时getUser()无法获取用户,抛出missing sub claim错误。刷新页面后浏览器已携带完整的Auth Cookie,因此能正常获取用户。
另外你的代码里存在一个小错误:checkIfUserExists(await user?.id)中的await是多余的,user已经是await getUser()的结果,无需再次异步等待。
解决方案
方案1:改用客户端组件处理Auth状态(推荐)
客户端组件可以监听Supabase的Auth状态变化,确保会话完全初始化后再执行用户存在性检查和跳转逻辑,避免服务器组件首次渲染时的会话延迟问题。
步骤1:创建客户端组件CompleteProfileClient.js
'use client'; import { useEffect, useState } from 'react'; import { createClientComponentClient } from '@supabase/auth-helpers-nextjs'; import { useRouter } from 'next/navigation'; import LeftColomn from "@/components/SignUp/LeftColomn/LeftColomn"; import RightColumnSeeker from "@/components/SignUp/RightColomnSeeker/RightColomnSeeker"; export default function CompleteProfileClient() { const [loading, setLoading] = useState(true); const router = useRouter(); const supabase = createClientComponentClient(); useEffect(() => { const checkAuthAndUser = async () => { // 监听Auth状态,确保会话就绪 const { data: { subscription } } = supabase.auth.onAuthStateChange(async (event, session) => { if (!session?.user) return; // 检查用户是否已存在于数据库 const { data } = await supabase .from('Seekers') .select() .eq('unique_id', session.user.id) .single(); if (data?.unique_id) { router.push('/all-jobs'); } else { setLoading(false); } subscription.unsubscribe(); }); // 立即检查当前会话 const { data: { user } } = await supabase.auth.getUser(); if (user) { subscription.unsubscribe(); const { data } = await supabase .from('Seekers') .select() .eq('unique_id', user.id) .single(); if (data?.unique_id) { router.push('/all-jobs'); } else { setLoading(false); } } }; checkAuthAndUser(); }, []); if (loading) { return <div>加载中...</div>; } return ( <div className="flex h-screen"> <LeftColomn /> <RightColumnSeeker /> </div> ); }
步骤2:修改原服务器组件CompleteProfile.js
import CompleteProfileClient from './CompleteProfileClient'; export default async function CompleteProfile() { return <CompleteProfileClient />; }
方案2:服务器组件添加错误重定向逻辑
如果坚持使用服务器组件,可以在getUser()失败时重定向到当前页面,触发重新渲染以获取完整的Auth会话:
import LeftColomn from "@/components/SignUp/LeftColomn/LeftColomn"; import RightColumnSeeker from "@/components/SignUp/RightColomnSeeker/RightColomnSeeker"; import getUser from "@/lib/getUser/getUser"; import { createServerComponentClient } from "@supabase/auth-helpers-nextjs"; import { cookies } from "next/headers"; import { redirect } from "next/navigation"; async function checkIfUserExists(id: string) { const supabase = createServerComponentClient({ cookies }) const { data, error } = await supabase .from('Seekers') .select() .eq('unique_id', id) .single() if (error) { console.log(error); } return data; } export default async function CompleteProfile() { const user = await getUser(); // 若获取用户失败,重定向刷新页面 if (!user) { redirect('/complete_profile?refresh=' + Date.now()); } const result = await checkIfUserExists(user.id); if (result?.unique_id) { redirect('/all-jobs') } else { return ( <div className="flex h-screen"> <LeftColomn /> <RightColumnSeeker /> </div> ) } }
额外注意事项
- 确保Supabase控制台的重定向URL已正确添加包含
/complete_profile的完整地址(如http://localhost:3000/complete_profile和生产环境URL)。 - 移除
getUser()函数中无意义的cookies().getAll()调用,避免不必要的性能开销。
内容的提问来源于stack exchange,提问作者Mohd Zaid
相关产品推荐
相关产品推荐

