基于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
相关产品推荐
相关产品推荐

