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

Django+PostgreSQL独立Schema多租户:认证与AUTH_USER_MODEL如何处理?

Django多租户SaaS分离认证与用户模型解决方案

一、基类继承方案(可行且推荐)

你考虑的基类继承方案完全可行,具体实现思路如下:

  • 定义继承AbstractUser的抽象基类BaseUser,只保留通用字段(如用户名、邮箱、密码),设置abstract = True,不作为AUTH_USER_MODEL。
  • 创建两个子类:GlobalAdmin(存储在public数据库,负责系统管理)和TenantUser(存储在对应租户Schema,关联租户内其他业务表),各自添加专属字段(比如GlobalAdmin加系统权限字段,TenantUser加租户关联字段)。
  • 配置Django数据库路由,确保GlobalAdmin始终路由到public数据库,TenantUser根据当前租户切换到对应Schema。

代码示例:

# models.py
from django.contrib.auth.models import AbstractUser
from django.db import models

class BaseUser(AbstractUser):
    class Meta:
        abstract = True

class GlobalAdmin(BaseUser):
    system_permissions = models.JSONField(default=dict)
    class Meta:
        db_table = 'global_admin'

class TenantUser(BaseUser):
    tenant_profile = models.ForeignKey('TenantProfile', on_delete=models.CASCADE)
    class Meta:
        db_table = 'tenant_user'

二、自定义认证后端(核心解决多模型认证问题)

Django允许配置多个认证后端,通过自定义后端实现分离认证逻辑,无需依赖单一AUTH_USER_MODEL:

  • 编写两个认证后端:GlobalAdminAuthBackend和TenantUserAuthBackend,分别处理两类用户的认证。
  • GlobalAdminAuthBackend直接操作public库的GlobalAdmin模型验证账号密码。
  • TenantUserAuthBackend先通过请求中的租户标识(如子域名、请求头)确定租户Schema,切换数据库连接后验证TenantUser的账号密码。
  • 在settings.py中注册这两个后端,注意顺序(全局管理员后端可优先)。

代码示例:

# backends.py
from django.contrib.auth.backends import ModelBackend
from .models import GlobalAdmin, TenantUser
from django.db import connections

class GlobalAdminAuthBackend(ModelBackend):
    def authenticate(self, request, username=None, password=None, **kwargs):
        try:
            # 指定使用public数据库
            user = GlobalAdmin.objects.using('public').get(username=username)
            if user.check_password(password):
                return user
        except GlobalAdmin.DoesNotExist:
            return None

class TenantUserAuthBackend(ModelBackend):
    def authenticate(self, request, username=None, password=None, **kwargs):
        # 从子域名提取租户标识
        tenant_id = request.get_host().split('.')[0]
        # 切换到对应租户Schema
        with connections['tenant'].schema_editor() as editor:
            editor.set_schema(tenant_id)
        try:
            user = TenantUser.objects.using('tenant').get(username=username)
            if user.check_password(password):
                return user
        except TenantUser.DoesNotExist:
            return None

settings配置:

AUTHENTICATION_BACKENDS = [
    'yourapp.backends.GlobalAdminAuthBackend',
    'yourapp.backends.TenantUserAuthBackend',
]
# 无需设置AUTH_USER_MODEL,由后端直接处理不同模型

三、路由级别的数据库隔离优化

将全局管理路由与租户路由分离,通过中间件提前切换数据库/Schema:

  • 全局管理员路由前缀设为/admin/,租户路由前缀设为/tenant/或使用独立子域名。
  • 编写中间件,根据请求路径或子域名判断请求类型,提前切换到对应数据库连接,避免认证后端重复切换操作。

四、关键注意事项

  • 数据库路由需精准配置,确保GlobalAdmin始终指向public库,TenantUser动态路由到对应租户Schema。
  • 区分两类用户的登录入口,比如全局管理员用/admin/login/,租户用户用/tenant/login/,避免认证逻辑冲突。
  • 权限控制分离:全局管理员使用Django默认权限系统,租户用户的权限在各自Schema内独立管理。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 00:54:52