refactor(admin): удален избыточный admin_access_middleware
- Удален TenantAdminAccessMiddleware (избыточен — Django Admin уже проверяет is_staff) - CustomUser.create_superuser теперь устанавливает is_staff=False (нет доступа к /admin/) - PlatformAdmin с is_staff=True сохраняет доступ к админке - Обновлен комментарий в onboarding.py Доступ к /admin/ теперь контролируется стандартным механизмом Django Admin через has_permission() + существующие authentication backends. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -21,14 +21,12 @@ class CustomUserManager(BaseUserManager):
|
|||||||
return user
|
return user
|
||||||
|
|
||||||
def create_superuser(self, email, name, password=None, **extra_fields):
|
def create_superuser(self, email, name, password=None, **extra_fields):
|
||||||
extra_fields.setdefault('is_staff', True)
|
extra_fields.setdefault('is_staff', False) # CustomUser не должен иметь доступ к Django Admin
|
||||||
extra_fields.setdefault('is_superuser', True)
|
extra_fields.setdefault('is_superuser', True)
|
||||||
extra_fields.setdefault('is_active', True)
|
extra_fields.setdefault('is_active', True)
|
||||||
# Суперпользователь автоматически имеет подтвержденный email
|
# Суперпользователь автоматически имеет подтвержденный email
|
||||||
extra_fields.setdefault('is_email_confirmed', True)
|
extra_fields.setdefault('is_email_confirmed', True)
|
||||||
|
|
||||||
if extra_fields.get('is_staff') is not True:
|
|
||||||
raise ValueError('Суперпользователь должен иметь is_staff=True.')
|
|
||||||
if extra_fields.get('is_superuser') is not True:
|
if extra_fields.get('is_superuser') is not True:
|
||||||
raise ValueError('Суперпользователь должен иметь is_superuser=True.')
|
raise ValueError('Суперпользователь должен иметь is_superuser=True.')
|
||||||
|
|
||||||
|
|||||||
@@ -1,98 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
"""
|
|
||||||
Middleware для ограничения доступа к админке.
|
|
||||||
|
|
||||||
SECURITY: Этот middleware обеспечивает изоляцию аутентификации между
|
|
||||||
PlatformAdmin (public schema) и CustomUser (tenant schemas).
|
|
||||||
|
|
||||||
Правила доступа к /admin/:
|
|
||||||
- На PUBLIC домене: только PlatformAdmin может входить
|
|
||||||
- На TENANT доменах: только PlatformAdmin с is_superuser=True (для поддержки)
|
|
||||||
или CustomUser с is_superuser=True (системный пользователь тенанта)
|
|
||||||
"""
|
|
||||||
from django.shortcuts import render
|
|
||||||
from django.db import connection
|
|
||||||
|
|
||||||
|
|
||||||
class TenantAdminAccessMiddleware:
|
|
||||||
"""
|
|
||||||
Middleware для контроля доступа к административным разделам.
|
|
||||||
|
|
||||||
Обеспечивает разделение между:
|
|
||||||
- PlatformAdmin (администраторы платформы) на public домене
|
|
||||||
- CustomUser (пользователи тенантов) на tenant доменах
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, get_response):
|
|
||||||
self.get_response = get_response
|
|
||||||
|
|
||||||
def _render_error(self, request, message):
|
|
||||||
"""Рендерит страницу ошибки доступа."""
|
|
||||||
return render(request, 'errors/access_denied.html', {
|
|
||||||
'message': message
|
|
||||||
}, status=403)
|
|
||||||
|
|
||||||
def __call__(self, request):
|
|
||||||
# Оптимизация: загружаем роль пользователя один раз для всего запроса
|
|
||||||
if hasattr(request, 'user') and request.user.is_authenticated:
|
|
||||||
schema_name = getattr(connection, 'schema_name', 'public')
|
|
||||||
# Только для tenant схем и CustomUser загружаем роль с select_related
|
|
||||||
if schema_name != 'public':
|
|
||||||
from accounts.models import CustomUser
|
|
||||||
if isinstance(request.user, CustomUser):
|
|
||||||
# Проверяем, не загружена ли уже роль
|
|
||||||
if not hasattr(request.user, '_role_prefetched'):
|
|
||||||
try:
|
|
||||||
# Загружаем пользователя с ролью через select_related
|
|
||||||
request.user = CustomUser.objects.select_related(
|
|
||||||
'tenant_role__role'
|
|
||||||
).get(pk=request.user.pk)
|
|
||||||
request.user._role_prefetched = True
|
|
||||||
except CustomUser.DoesNotExist:
|
|
||||||
pass
|
|
||||||
|
|
||||||
# Проверяем, это admin URL?
|
|
||||||
if request.path.startswith('/admin/'):
|
|
||||||
# Импортируем здесь чтобы избежать circular imports
|
|
||||||
from platform_admin.models import PlatformAdmin
|
|
||||||
|
|
||||||
# Получаем текущую schema
|
|
||||||
schema_name = getattr(connection, 'schema_name', 'public')
|
|
||||||
is_public = schema_name == 'public'
|
|
||||||
|
|
||||||
# Проверяем наличие атрибута user (добавляется AuthenticationMiddleware)
|
|
||||||
if hasattr(request, 'user') and request.user.is_authenticated:
|
|
||||||
user = request.user
|
|
||||||
is_platform_admin = isinstance(user, PlatformAdmin)
|
|
||||||
|
|
||||||
if is_public:
|
|
||||||
# PUBLIC DOMAIN: только PlatformAdmin
|
|
||||||
if not is_platform_admin:
|
|
||||||
return self._render_error(
|
|
||||||
request,
|
|
||||||
'Административная панель платформы доступна только '
|
|
||||||
'для администраторов платформы. '
|
|
||||||
'Если вы владелец магазина, перейдите на домен вашего магазина.'
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
# TENANT DOMAIN: PlatformAdmin (superuser) или CustomUser (superuser)
|
|
||||||
if is_platform_admin:
|
|
||||||
# PlatformAdmin на tenant домене - только суперадмин
|
|
||||||
if not user.is_superuser:
|
|
||||||
return self._render_error(
|
|
||||||
request,
|
|
||||||
'Только суперадминистраторы платформы '
|
|
||||||
'могут получить доступ к этому разделу.'
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
# CustomUser на tenant домене
|
|
||||||
if not user.is_superuser:
|
|
||||||
return self._render_error(
|
|
||||||
request,
|
|
||||||
'Только системные администраторы тенанта '
|
|
||||||
'могут получить доступ к этому разделу. '
|
|
||||||
'Используйте панель управления магазином.'
|
|
||||||
)
|
|
||||||
|
|
||||||
response = self.get_response(request)
|
|
||||||
return response
|
|
||||||
@@ -126,7 +126,6 @@ MIDDLEWARE = [
|
|||||||
'django.middleware.common.CommonMiddleware',
|
'django.middleware.common.CommonMiddleware',
|
||||||
'django.middleware.csrf.CsrfViewMiddleware',
|
'django.middleware.csrf.CsrfViewMiddleware',
|
||||||
'django.contrib.auth.middleware.AuthenticationMiddleware', # 4. Определение пользователя
|
'django.contrib.auth.middleware.AuthenticationMiddleware', # 4. Определение пользователя
|
||||||
'myproject.admin_access_middleware.TenantAdminAccessMiddleware', # 5. ТЕПЕРЬ проверка работает (после auth)
|
|
||||||
'django.contrib.messages.middleware.MessageMiddleware',
|
'django.contrib.messages.middleware.MessageMiddleware',
|
||||||
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
||||||
'simple_history.middleware.HistoryRequestMiddleware',
|
'simple_history.middleware.HistoryRequestMiddleware',
|
||||||
|
|||||||
@@ -231,7 +231,7 @@ class TenantOnboardingService:
|
|||||||
# 2. Техподдержка платформы
|
# 2. Техподдержка платформы
|
||||||
# SECURITY: НЕ создаём отдельную учетку CustomUser для саппорта
|
# SECURITY: НЕ создаём отдельную учетку CustomUser для саппорта
|
||||||
# PlatformAdmin с is_superuser=True уже имеет полный доступ к tenant
|
# PlatformAdmin с is_superuser=True уже имеет полный доступ к tenant
|
||||||
# через PlatformAdminBackend и TenantAdminAccessMiddleware
|
# через PlatformAdminBackend (может залогиниться и зайти в /admin/)
|
||||||
logger.info("Техподдержка: используется PlatformAdmin (отдельный CustomUser НЕ создаётся)")
|
logger.info("Техподдержка: используется PlatformAdmin (отдельный CustomUser НЕ создаётся)")
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|||||||
Reference in New Issue
Block a user