如何在Next.js API路由中实现Supabase认证查询?
解决Supabase服务器端JWT认证与RLS适配问题
问题核心
你遇到的问题主要出在JWT的处理方式和createServerSupabaseClient的用法上:
- 传递给
supabase.auth.getUser()的是带Bearer前缀的完整请求头,而非纯JWT字符串; - 使用
createServerSupabaseClient时无需手动传入JWT,该工具会自动解析请求中的认证信息; - 缺乏关键的认证错误处理,导致用户未认证时无法返回正确状态。
修正后的服务器端代码
export default async function handler( req: NextApiRequest, res: NextApiResponse<Data | string> ) { try { const word = req.body; // 创建服务器端Supabase客户端,自动从请求中提取认证信息 const supabase = createServerSupabaseClient({ req, res }); // 获取当前认证用户,无需手动传递JWT const { data: { user }, error: authError } = await supabase.auth.getUser(); // 处理未认证或认证失败的情况 if (authError || !user) { return res.status(401).send("Unauthorized"); } // 检查当前用户名下是否已存在该单词(匹配RLS规则) const { count, error: countError } = await supabase .from("words") .select("name", { head: true, count: "exact" }) .eq("name", word) .eq("user_id", user.id); if (countError) throw countError; if (count) { return res.status(409).send("Word already saved"); } // 插入数据并关联当前用户ID const { data, error: insertError } = await supabase .from("words") .insert({ name: word, user_id: user.id }); if (insertError) throw insertError; res.status(200).send("OK"); } catch (err) { console.error(err); res.status(500).send("Something went wrong!"); } }
关键改动说明
- 自动认证处理:
createServerSupabaseClient会自动识别请求中的Authorization头或Supabase认证Cookie,无需手动提取JWT; - 正确获取用户:调用
supabase.auth.getUser()无需参数,直接返回当前认证用户,同时增加认证失败的判断,及时返回401未授权状态; - 匹配RLS规则:查询单词时添加
user_id过滤条件,确保只检查当前用户的数据,和你设置的行级安全规则对齐; - 完善错误捕获:为每个数据库操作添加错误处理,避免未捕获异常导致的500错误。
客户端代码优化
客户端无需将JWT作为apiKey传递,apiKey应使用项目的公开匿名密钥:
const session = await supabase.auth.getSession(); const jwt = session.data.session?.access_token; try { const response = await fetch(`/api/word/${route}`, { method, headers: { "Content-Type": "application/json", Authorization: `Bearer ${jwt}`, apiKey: process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY, }, body: JSON.stringify(word), }); } catch (err) { console.error("Request failed:", err); }
内容的提问来源于stack exchange,提问作者gxk28
相关产品推荐
相关产品推荐

