无法从Clerk中间件获取用户邮箱,无法更新Supabase用户表
解决Clerk中间件中无法获取用户邮箱的问题
你的核心问题是在服务器端的Clerk中间件中误用了客户端API——getUser和getAuth都是@clerk/nextjs/client下的浏览器端方法,在服务器环境调用无法正确获取用户数据,自然拿不到邮箱。
正确解决方案:使用Clerk服务器端API
Clerk为服务器端场景提供了专门的API,你可以通过两种方式获取用户邮箱:
方式1:直接从auth()获取用户对象
Clerk中间件的auth()方法本身就会返回包含用户完整信息的对象,无需额外调用其他方法:
import { clerkMiddleware } from "@clerk/nextjs/server"; import { NextResponse } from "next/server"; import { supabase } from "./utils/supabase/supabase"; const isProtectedRoute = (req) => { const protectedPaths = ["/add-listing", "/(api|trpc)(.*)"]; return protectedPaths.some((path) => req.url.includes(path)); }; export default clerkMiddleware(async (auth, req) => { console.log("Middleware is triggered"); const { userId, user } = auth() || {}; console.log("userId:", userId); console.log("User info:", user); if (userId && user) { console.log("User is authenticated:", userId); // 从user对象提取邮箱(优先取已验证的) const email = user.emailAddresses.find(e => e.verified)?.emailAddress || user.emailAddresses[0].emailAddress; const authId = userId; console.log("Email:", email); console.log("authId:", authId); const { error } = await supabase.from("Users").upsert({ email, authId }); if (error) { console.error("Error inserting user into Supabase:", error); } else { console.log("User inserted or updated in Supabase successfully"); } } else { console.log("User is not authenticated"); } if (isProtectedRoute(req) && !userId) { return new Response("Unauthorized", { status: 401 }); } return NextResponse.next(); }); export const config = { matcher: [ "/add-listing", "/(api|trpc)(.*)", "/((?!_next|.*\\.).*)", ] };
方式2:使用服务器端的getUser方法
如果你需要单独获取用户信息,可以从@clerk/nextjs/server导入服务器端的getUser:
import { clerkMiddleware, getUser } from "@clerk/nextjs/server"; import { NextResponse } from "next/server"; import { supabase } from "./utils/supabase/supabase"; const isProtectedRoute = (req) => { const protectedPaths = ["/add-listing", "/(api|trpc)(.*)"]; return protectedPaths.some((path) => req.url.includes(path)); }; export default clerkMiddleware(async (auth, req) => { console.log("Middleware is triggered"); const { userId } = auth() || {}; console.log("userId:", userId); if (userId) { console.log("User is authenticated:", userId); // 调用服务器端API获取用户数据 const user = await getUser(userId); // 提取邮箱(优先取已验证的) const email = user.emailAddresses.find(e => e.verified)?.emailAddress || user.emailAddresses[0].emailAddress; const authId = userId; console.log("Email:", email); console.log("authId:", authId); const { error } = await supabase.from("Users").upsert({ email, authId }); if (error) { console.error("Error inserting user into Supabase:", error); } else { console.log("User inserted or updated in Supabase successfully"); } } else { console.log("User is not authenticated"); } if (isProtectedRoute(req) && !userId) { return new Response("Unauthorized", { status: 401 }); } return NextResponse.next(); }); export const config = { matcher: [ "/add-listing", "/(api|trpc)(.*)", "/((?!_next|.*\\.).*)", ] };
关键注意点
- 严格区分Clerk的客户端/服务器端API:
@clerk/nextjs/client下的方法仅适用于浏览器组件,服务器端代码(中间件、API路由、Server Components)必须使用@clerk/nextjs/server下的API。 - 用户邮箱存储在
user.emailAddresses数组中(Clerk支持多邮箱),建议优先选取verified: true的邮箱,避免使用未验证的邮箱。
内容的提问来源于stack exchange,提问作者Anteneh Debebe Bekele
相关产品推荐
相关产品推荐

