You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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作为认证凭证是更可靠的选择:

  1. 主站完成认证后,生成包含租户ID、用户ID的JWT返回给前端
  2. 前端将JWT存储在本地,每次请求租户接口时,在Authorization头中携带Bearer {token}
  3. 租户应用编写中间件,验证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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 12:12:50