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:
2026-01-11 22:00:14 +03:00
parent a1e81b97bf
commit b562eabcaf
4 changed files with 2 additions and 103 deletions

View File

@@ -21,14 +21,12 @@ class CustomUserManager(BaseUserManager):
return user
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_active', True)
# Суперпользователь автоматически имеет подтвержденный email
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:
raise ValueError('Суперпользователь должен иметь is_superuser=True.')

View File

@@ -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

View File

@@ -126,7 +126,6 @@ MIDDLEWARE = [
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware', # 4. Определение пользователя
'myproject.admin_access_middleware.TenantAdminAccessMiddleware', # 5. ТЕПЕРЬ проверка работает (после auth)
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'simple_history.middleware.HistoryRequestMiddleware',

View File

@@ -231,7 +231,7 @@ class TenantOnboardingService:
# 2. Техподдержка платформы
# SECURITY: НЕ создаём отдельную учетку CustomUser для саппорта
# PlatformAdmin с is_superuser=True уже имеет полный доступ к tenant
# через PlatformAdminBackend и TenantAdminAccessMiddleware
# через PlatformAdminBackend (может залогиниться и зайти в /admin/)
logger.info("Техподдержка: используется PlatformAdmin (отдельный CustomUser НЕ создаётся)")
@classmethod