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

基于NextAuth实现多租户子域名差异化登录的可行性咨询

用NextAuth实现多租户子域名独立登录方案

完全可以通过NextAuth实现你的需求,核心是利用NextAuth的动态配置能力和Next.js的子域名路由支持,区分平台用户与租户客户的登录流程。以下是具体实现步骤:

1. 配置Next.js支持子域名路由

先通过中间件解析子域名,将子域名请求重写到对应路由,方便后续区分处理:

// middleware.js
import { NextResponse } from 'next/server';

export function middleware(request) {
  const hostname = request.headers.get('host');
  const subdomain = hostname.split('.')[0];
  
  // 跳过主域名app.mywebsite.com的路由重写
  if (subdomain !== 'app') {
    request.nextUrl.pathname = `/tenant/${subdomain}${request.nextUrl.pathname}`;
    return NextResponse.rewrite(request.nextUrl);
  }
  return NextResponse.next();
}

比如访问user1.mywebsite.com/login会被重写到/tenant/user1/login。

2. 动态切换NextAuth登录配置

在NextAuth的API路由中,根据当前请求的子域名,加载不同的登录提供商和配置:

// app/api/auth/[...nextauth]/route.js
import NextAuth from 'next-auth';
import CredentialsProvider from 'next-auth/providers/credentials';
import GoogleProvider from 'next-auth/providers/google';

export async function GET(request) {
  const hostname = request.headers.get('host');
  const subdomain = hostname.split('.')[0];

  let providers = [];
  // 平台用户(app.mywebsite.com)用Google/GitHub登录
  if (subdomain === 'app') {
    providers = [
      GoogleProvider({
        clientId: process.env.GOOGLE_CLIENT_ID,
        clientSecret: process.env.GOOGLE_CLIENT_SECRET,
      }),
      // 可添加GitHub等其他第三方提供商
    ];
  } 
  // 租户客户(xxx.mywebsite.com)用邮箱密码登录
  else {
    providers = [
      CredentialsProvider({
        name: 'Credentials',
        credentials: {
          email: { label: '邮箱', type: 'email' },
          password: { label: '密码', type: 'password' },
        },
        async authorize(credentials) {
          // 根据子域名查询对应租户的客户数据库,验证账号
          const user = await fetchTenantUser(subdomain, credentials.email);
          if (user && await verifyPassword(user.password, credentials.password)) {
            return user;
          }
          return null;
        },
      }),
    ];
  }

  return NextAuth(request, {
    providers,
    session: { strategy: 'jwt' },
    callbacks: {
      async session({ session, token }) {
        // 将租户标识加入session,后续业务逻辑可据此区分租户
        session.tenant = subdomain;
        return session;
      },
    },
    // 为不同子域名指定专属登录页面
    pages: {
      signIn: subdomain === 'app' ? '/login' : `/tenant/${subdomain}/login`,
    },
  });
}

3. 自定义租户专属登录页面

在app/tenant/[subdomain]/login路径下创建动态页面,根据子域名加载租户的品牌配置(如logo、配色):

// app/tenant/[subdomain]/login/page.js
import { getServerSession } from 'next-auth/next';
import { authOptions } from '../../api/auth/[...nextauth]/route';
import { useRouter, useParams } from 'next/navigation';

export default async function TenantLoginPage() {
  const session = await getServerSession(authOptions);
  const router = useRouter();
  const { subdomain } = useParams();

  // 已登录则跳转到租户客户仪表盘
  if (session) {
    router.push(`/tenant/${subdomain}/dashboard`);
    return null;
  }

  // 从数据库获取租户的品牌配置
  const tenantConfig = await fetchTenantConfig(subdomain);

  return (
    <div style={{ backgroundColor: tenantConfig.primaryColor, padding: '2rem' }}>
      <img src={tenantConfig.logoUrl} alt={`${tenantConfig.name} 品牌标识`} style={{ width: '120px' }} />
      <h1 style={{ color: tenantConfig.textColor }}>登录{tenantConfig.name}客户平台</h1>
      <form action="/api/auth/signin/credentials" method="post" style={{ marginTop: '1.5rem' }}>
        <input 
          type="email" 
          name="email" 
          placeholder="请输入邮箱" 
          required 
          style={{ display: 'block', marginBottom: '0.8rem', padding: '0.6rem' }}
        />
        <input 
          type="password" 
          name="password" 
          placeholder="请输入密码" 
          required 
          style={{ display: 'block', marginBottom: '0.8rem', padding: '0.6rem' }}
        />
        <button 
          type="submit" 
          style={{ backgroundColor: tenantConfig.buttonColor, color: '#fff', padding: '0.6rem 1.2rem', border: 'none', borderRadius: '4px' }}
        >
          登录
        </button>
      </form>
    </div>
  );
}

4. 跨子域名Cookie配置(可选)

如果需要让平台用户的session在租户子域名中生效,可配置NextAuth的Cookie域为根域名(.mywebsite.com),注意需确保HTTPS环境:

// 在NextAuth配置中添加cookies字段
cookies: {
  sessionToken: {
    name: `__Secure-next-auth.session-token`,
    domain: '.mywebsite.com',
    path: '/',
    secure: true,
    httpOnly: true,
    sameSite: 'lax',
  },
},

此配置需谨慎使用,避免租户客户与平台用户的session权限混淆,建议为不同用户类型设置独立的权限校验逻辑。

内容的提问来源于stack exchange,提问作者didu bako

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 13:35:28