django-Tenant:限制访问公共模式

发布于 2025-01-23 11:44:09 字数 3464 浏览 0 评论 0原文

我正在尝试使用此 django--- django----- django-----租户包裹。

而且我已经按照示例视频设置了演示: video1 video2

app clients(models.py)

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


class Client(TenantMixin):
    name = models.CharField("Customer name", max_length=100)       
    created_on = models.DateField(auto_now_add=True)

    # default true, schema will be automatically created and synced when it is saved
    auto_create_schema = True    


class Domain(DomainMixin):
    pass

app app sweet_tenant(models.py)

from django.db import models

from applications.sweet_shared.models import SweetType

class Sweet(models.Model):
    sweet_type = models.ForeignKey(SweetType, on_delete=models.CASCADE)
    name = models.CharField(max_length=50)
    price = models.DecimalField(default=0, decimal_places=3, max_digits=8)

    def __str__(self):
        return self.name

app sweet_shared(models.py)

from django.db import models

class SweetType(models.Model):
    name = models.CharField(max_length=20)    

    def __str__(self):
        return self.name

设置

# Application definition
SHARED_APPS = [
    "django_tenants", # mandatory 
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    # shared apps
    "applications.clients",    
    "applications.sweet_shared",
    
]

TENANT_APPS = (   
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    # your tenant-specific apps 
    "applications.sweet_tenant",
)

INSTALLED_APPS = SHARED_APPS + [app for app in TENANT_APPS if app not in SHARED_APPS] 

行为

公共模式与所有租户共享。如果您不过滤,任何租户都可以看到任何数据表格公共模式。 正常行为

这是公共模式中创建的

租户(客户)。 需要

我不希望任何租户都可以看到这些数据(租户),因为它将包含私人客户数据。每个租户只需要查看他的数据,只有SaaS所有者才能看到所有数据(公共模式中的超级用户)。

问题

我已将此代码(请参见下面的代码)添加到 admin.py 文件中以过滤房客的数据。这很好。但是问题在于,我无法检测到它何时不是租户,并且是公共模式的超级用户。还是有更好的方法可以实现它?

from django.contrib import admin
from django_tenants.admin import TenantAdminMixin
from django.db import connection

from .models import Client   


class ClientAdmin(TenantAdminMixin, admin.ModelAdmin):
    list_display = (
        "name",
        "schema_name",
        "created_on",
    )

    def get_readonly_fields(self, request, obj=None):            
        if obj: # editing an existing object
            return self.readonly_fields + ('schema_name', 'created_on')
        
        return self.readonly_fields


    def get_queryset(self, request):
        qs = super().get_queryset(request)            
        return qs.filter(name=connection.tenant)           
            

admin.site.register(Client, ClientAdmin)

I am trying to create a multi tenant app (with shared database and isolated schema) using this Django-Tenants package.

And I've followed the example videos to setup a demo: video1 and video2

app clients (models.py)

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


class Client(TenantMixin):
    name = models.CharField("Customer name", max_length=100)       
    created_on = models.DateField(auto_now_add=True)

    # default true, schema will be automatically created and synced when it is saved
    auto_create_schema = True    


class Domain(DomainMixin):
    pass

app sweet_tenant (models.py)

from django.db import models

from applications.sweet_shared.models import SweetType

class Sweet(models.Model):
    sweet_type = models.ForeignKey(SweetType, on_delete=models.CASCADE)
    name = models.CharField(max_length=50)
    price = models.DecimalField(default=0, decimal_places=3, max_digits=8)

    def __str__(self):
        return self.name

app sweet_shared (models.py)

from django.db import models

class SweetType(models.Model):
    name = models.CharField(max_length=20)    

    def __str__(self):
        return self.name

settings

# Application definition
SHARED_APPS = [
    "django_tenants", # mandatory 
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    # shared apps
    "applications.clients",    
    "applications.sweet_shared",
    
]

TENANT_APPS = (   
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    # your tenant-specific apps 
    "applications.sweet_tenant",
)

INSTALLED_APPS = SHARED_APPS + [app for app in TENANT_APPS if app not in SHARED_APPS] 

BEHAVIOUR

Public schema are shared with all tenants. Any tenant can see any data form public schema if you don't filter. This is a normal behavior

Tenants (clients) are created in the public schema.

NEEDS

I dont want that these data (tenants) can be seen by any tenant, because it will contain private client data. Each tenant only needs to see his data and only the SaaS owner can see all data (superuser in public schema).

PROBLEM

I have added this code (see code below) into the admin.py file to filter tenant's data. This works fine. But the problem is that I have not been able to detect when it is not a tenant and is the superuser of the public schema. Or is there a better way to achieve it?

from django.contrib import admin
from django_tenants.admin import TenantAdminMixin
from django.db import connection

from .models import Client   


class ClientAdmin(TenantAdminMixin, admin.ModelAdmin):
    list_display = (
        "name",
        "schema_name",
        "created_on",
    )

    def get_readonly_fields(self, request, obj=None):            
        if obj: # editing an existing object
            return self.readonly_fields + ('schema_name', 'created_on')
        
        return self.readonly_fields


    def get_queryset(self, request):
        qs = super().get_queryset(request)            
        return qs.filter(name=connection.tenant)           
            

admin.site.register(Client, ClientAdmin)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

倾城泪 2025-01-30 11:44:09

您可以将以下Mixin添加到clientAdmin中,只允许公共租户查看您的客户端和域数据。

from django.contrib import admin
from django_tenants.admin import TenantAdminMixin
from django_tenants.utils import get_public_schema_name

from backend.customers.models import Client, Domain

class PublicTenantOnlyMixin:
        """Allow Access to Public Tenant Only."""
        def _only_public_tenant_access(self, request):
                return True if request.tenant.schema_name == get_public_schema_name() else False
        
        def has_view_permission(self,request, view=None):
                return self._only_public_tenant_access( request)
        
        def has_add_permission(self,request, view=None):
                return self._only_public_tenant_access(request)
        
        def has_change_permission(self,request, view=None):
                return self._only_public_tenant_access( request)
        
        def has_delete_permission(self,request, view=None):
                return self._only_public_tenant_access( request)
        
        def has_view_or_change_permission(self,request, view=None):
                return self._only_public_tenant_access( request)

@admin.register(Client)
class ClientAdmin(PublicTenantOnlyMixin,TenantAdminMixin, admin.ModelAdmin):
        list_display = ('name', 'paid_until')
        
@admin.register(Domain)
class DomainAdmin(PublicTenantOnlyMixin,TenantAdminMixin, admin.ModelAdmin):
        list_display = ('domain',)

You can add the following Mixin to the ClientAdmin to only allow public tenants to see your clients and domains data.

from django.contrib import admin
from django_tenants.admin import TenantAdminMixin
from django_tenants.utils import get_public_schema_name

from backend.customers.models import Client, Domain

class PublicTenantOnlyMixin:
        """Allow Access to Public Tenant Only."""
        def _only_public_tenant_access(self, request):
                return True if request.tenant.schema_name == get_public_schema_name() else False
        
        def has_view_permission(self,request, view=None):
                return self._only_public_tenant_access( request)
        
        def has_add_permission(self,request, view=None):
                return self._only_public_tenant_access(request)
        
        def has_change_permission(self,request, view=None):
                return self._only_public_tenant_access( request)
        
        def has_delete_permission(self,request, view=None):
                return self._only_public_tenant_access( request)
        
        def has_view_or_change_permission(self,request, view=None):
                return self._only_public_tenant_access( request)

@admin.register(Client)
class ClientAdmin(PublicTenantOnlyMixin,TenantAdminMixin, admin.ModelAdmin):
        list_display = ('name', 'paid_until')
        
@admin.register(Domain)
class DomainAdmin(PublicTenantOnlyMixin,TenantAdminMixin, admin.ModelAdmin):
        list_display = ('domain',)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文