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

如何通过django-tenant-users在Django中实现租户数据与功能隔离?

解决Django多租户(django-tenant + django-tenant-users)的租户隔离问题

你的思路方向是对的,但要实现全面的租户隔离,需要从全局校验、模型绑定、查询过滤、视图加固多个层面组合实施,以下是具体实操方案:

1. 优化租户认证中间件

你现有的中间件可以优化查询效率,同时处理匿名用户和无租户的场景:

from django.core.exceptions import PermissionDenied
from django_tenants.utils import get_current_tenant

class TenantAuthMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        tenant = get_current_tenant()
        # 无租户上下文直接拒绝(可根据公开资源需求调整)
        if not tenant:
            raise PermissionDenied("No tenant context found")
            
        if request.user.is_authenticated:
            # 用exists()替代in操作,避免全表查询
            if not request.user.tenants.filter(pk=tenant.pk).exists():
                raise PermissionDenied("You don't have access to this tenant")

        response = self.get_response(request)
        return response

注意:这个中间件要放在django-tenant自带的TenantMiddleware之后,确保request.tenant已经被正确设置。

2. 模型层强制租户关联

所有属于租户的业务模型必须绑定租户外键,从根源上确保数据归属:

from django.db import models
from django_tenants.models import TenantMixin

# 自定义租户模型
class Client(TenantMixin):
    name = models.CharField(max_length=100)
    paid_until = models.DateField(null=True, blank=True)
    on_trial = models.BooleanField(default=True)
    auto_create_schema = True  # 自动创建租户schema

# 业务模型示例:所有租户数据必须关联Client
class Project(models.Model):
    tenant = models.ForeignKey(Client, on_delete=models.CASCADE, related_name="projects")
    name = models.CharField(max_length=200)
    description = models.TextField(null=True, blank=True)

    def __str__(self):
        return self.name

3. 自动过滤租户查询集

自定义模型Manager,让所有默认查询自动过滤当前租户的数据,避免视图中重复写过滤逻辑:

from django.db import models
from django_tenants.utils import get_current_tenant

class TenantManager(models.Manager):
    def get_queryset(self):
        queryset = super().get_queryset()
        tenant = get_current_tenant()
        if tenant:
            return queryset.filter(tenant=tenant)
        # 无租户上下文时返回空集(或按需调整)
        return queryset.none()

# 业务模型中使用该Manager
class Project(models.Model):
    # ... 字段定义
    objects = TenantManager()

这样无论你在视图中调用Project.objects.all()还是Project.objects.get(pk=1),都会自动过滤当前租户的数据。

4. 结合django-tenant-users的用户-租户关联

确保用户和租户的多对多关系正确维护,django-tenant-users提供了TenantUser模型来关联用户和租户:

from django_tenant_users.tenants.models import TenantUser
from django.contrib.auth.models import User

# 创建用户并关联租户
def create_tenant_user(tenant, username, password):
    user = User.objects.create_user(username=username, password=password)
    # 绑定用户到租户
    TenantUser.objects.create(user=user, tenant=tenant)
    return user

同时,确保用户模型的tenants反向关联可用(django-tenant-users默认已配置),这样request.user.tenants能正确返回用户所属的租户列表。

5. 视图层加固权限

使用Mixin装饰器,在视图层面二次校验租户权限,防止绕过中间件的场景:

from django.core.exceptions import PermissionDenied
from django.views.generic.base import ViewMixin
from django_tenants.utils import get_current_tenant

class TenantPermissionMixin(ViewMixin):
    def dispatch(self, request, *args, **kwargs):
        tenant = get_current_tenant()
        if not tenant:
            raise PermissionDenied
        if request.user.is_authenticated and not request.user.tenants.filter(pk=tenant.pk).exists():
            raise PermissionDenied
        return super().dispatch(request, *args, **kwargs)

# 在视图中使用
class ProjectListView(TenantPermissionMixin, ListView):
    model = Project
    template_name = "projects/list.html"

6. 管理后台租户隔离

如果使用Django Admin,需要自定义ModelAdmin来过滤租户数据:

from django.contrib import admin
from django_tenants.utils import get_current_tenant
from .models import Project

class ProjectAdmin(admin.ModelAdmin):
    list_display = ("name", "tenant")
    
    def get_queryset(self, request):
        qs = super().get_queryset(request)
        tenant = get_current_tenant()
        if tenant:
            return qs.filter(tenant=tenant)
        return qs.none()

admin.site.register(Project, ProjectAdmin)

总结

以上方案组合起来,从全局请求校验、模型数据绑定、自动查询过滤、视图权限加固、后台数据隔离五个层面实现了完整的租户隔离,确保租户用户无法访问其他租户的数据或功能。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 01:49:54