如何在Vercel多租户平台启动工具包中实现子域/自定义域用户认证?
适配Next.js 13多租户(子域/自定义域)的认证方案
针对你使用Vercel Next.js 13多租户模板时遇到的租户应用认证问题(现有NextAuth/Auth0不支持自定义域),以下是几种可行的解决方案:
方案一:改造NextAuth.js支持多域名动态配置
NextAuth本身可以通过动态配置适配多域名,核心是根据请求域名动态调整认证参数:
- 动态设置
NEXTAUTH_URL:不要在环境变量中硬写固定值,而是从请求的host头动态生成 - 调整回调逻辑:允许当前请求域名的合法回调跳转
- Cookie适配:子域场景可设置Cookie的
domain为通配符(如.mydomain.com),实现子域间Cookie共享;自定义域场景建议改用JWT会话策略,避免跨域Cookie限制
示例配置代码:
import NextAuth from "next-auth" import { headers } from "next/headers" export default NextAuth({ providers: [/* 你的认证提供商配置 */], callbacks: { async redirect({ url }) { const requestHost = headers().get("host") || "" const currentBaseUrl = `https://${requestHost}` // 仅允许跳转至当前请求域名下的地址 if (url.startsWith(currentBaseUrl)) return url return currentBaseUrl }, async session({ session, token }) { // 注入租户ID等信息到会话中 session.tenantId = token.tenantId return session } }, session: { strategy: "jwt" }, // 自定义域场景必须用JWT secret: process.env.NEXTAUTH_SECRET, })
方案二:自定义JWT认证中间件(全场景适配)
对于自定义域这类跨域场景,Cookie无法共享,用JWT作为认证凭证是更可靠的选择:
- 主站完成认证后,生成包含租户ID、用户ID的JWT返回给前端
- 前端将JWT存储在本地,每次请求租户接口时,在
Authorization头中携带Bearer {token} - 租户应用编写中间件,验证JWT有效性,并校验Token中的租户ID与当前请求域名的映射关系(需在数据库中维护域名-租户的关联)
示例中间件代码:
import { NextRequest, NextResponse } from "next/server" import jwt from "jsonwebtoken" export async function middleware(request: NextRequest) { const token = request.headers.get("Authorization")?.split(" ")[1] if (!token) { return NextResponse.redirect(new URL("/login", request.url)) } try { const decoded = jwt.verify(token, process.env.JWT_SECRET!) as { tenantId: string; userId: string } // 从数据库查询当前域名对应的租户ID const tenant = await fetch(process.env.API_URL + "/api/tenants/domain/" + request.nextUrl.host).then(res => res.json()) if (!tenant || tenant.id !== decoded.tenantId) { return NextResponse.redirect(new URL("/unauthorized", request.url)) } // 将租户和用户信息注入请求头,供后续路由使用 const headers = new Headers(request.headers) headers.set("x-tenant-id", decoded.tenantId) headers.set("x-user-id", decoded.userId) return NextResponse.next({ request: { headers } }) } catch (err) { return NextResponse.redirect(new URL("/login", request.url)) } } export const config = { matcher: ["/dashboard/:path*", "/api/:path*"], // 需保护的路由 }
方案三:使用原生支持多租户自定义域的第三方服务
如果不想自己维护认证逻辑,直接选择开箱即用的第三方服务:
- Clerk:原生支持多租户架构,允许每个租户配置自定义域名,提供完善的Next.js App Router集成,无需额外改造即可适配子域/自定义域
- Supabase Auth:通过自定义域名配置结合行级安全(RLS),实现租户数据隔离,支持跨域认证场景
- Stytch:专注于身份认证的服务,支持多租户自定义域名,提供多种认证方式(密码、OTP、社交登录等)
内容的提问来源于stack exchange,提问作者Zain Khalid
相关产品推荐
相关产品推荐

