From d90b0162c50e2836c5a5da569876a99ebea4ec91 Mon Sep 17 00:00:00 2001 From: Andrey Smakotin Date: Fri, 9 Jan 2026 23:50:19 +0300 Subject: [PATCH] =?UTF-8?q?fix:=20=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B0=20=D0=B2=D1=82=D0=BE=D1=80=D0=B0=D1=8F?= =?UTF-8?q?=20=D0=BE=D1=88=D0=B8=D0=B1=D0=BA=D0=B0=20-=20=D0=BE=D1=82?= =?UTF-8?q?=D0=BA=D0=BB=D1=8E=D1=87=D0=B5=D0=BD=20ModelBackend=20=D0=B4?= =?UTF-8?q?=D0=BB=D1=8F=20CustomUser?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Проблема: После первого исправления ошибка продолжалась, но теперь в другом месте. Django's ModelBackend пытался проверить permissions для CustomUser через Permission.objects.filter(group__user=user_obj), что вызывало ошибку "Cannot query 'chupa@chus.by': Must be 'PlatformAdmin' instance" Причина: RoleBasedPermissionBackend наследует ModelBackend, и для CustomUser все равно вызывался super().has_perm(), который обращался к Django Permission таблице в public schema, ожидая PlatformAdmin. Решение: Полностью отключен вызов super().has_perm() и super().has_module_perms() для CustomUser. Теперь для CustomUser используется только role-based permission checking, а для PlatformAdmin - стандартный ModelBackend. Изменения в user_roles/auth_backend.py: - has_perm(): добавлена ветка if is_tenant, которая полностью обрабатывает CustomUser без вызова super() - has_module_perms(): аналогичная логика - Для PlatformAdmin сохранена проверка через super() (ModelBackend) Co-Authored-By: Claude Sonnet 4.5 --- myproject/user_roles/auth_backend.py | 101 ++++++++++++++------------- 1 file changed, 53 insertions(+), 48 deletions(-) diff --git a/myproject/user_roles/auth_backend.py b/myproject/user_roles/auth_backend.py index 81f387b..d699ac4 100644 --- a/myproject/user_roles/auth_backend.py +++ b/myproject/user_roles/auth_backend.py @@ -99,45 +99,46 @@ class RoleBasedPermissionBackend(ModelBackend): if not user_obj.is_authenticated: return False - # Для CustomUser (пользователи тенантов) пропускаем стандартную проверку Django permissions - # т.к. AUTH_USER_MODEL = PlatformAdmin, и super().has_perm() будет пытаться - # искать permissions для PlatformAdmin, а не для CustomUser + # Определяем тип пользователя is_tenant = _is_tenant_user(user_obj) - if not is_tenant: - # Для PlatformAdmin проверяем стандартные permissions через ModelBackend - if super().has_perm(user_obj, perm, obj): + # Для CustomUser (пользователи тенантов) НЕ вызываем super().has_perm() + # т.к. AUTH_USER_MODEL = PlatformAdmin, и ModelBackend будет пытаться + # искать permissions в Django Permission таблице для PlatformAdmin + if is_tenant: + # Суперпользователь имеет все права + if user_obj.is_superuser: return True - # Суперпользователь имеет все права - if user_obj.is_superuser: - return True + # ВАЖНО: В public схеме нет таблиц UserRole/Role! + if _is_public_schema(): + return False - # ВАЖНО: В public схеме нет таблиц UserRole/Role! - # Используем только стандартные Django permissions. - if _is_public_schema(): - return False + # Для CustomUser получаем роль пользователя в текущем тенанте + user_role = RoleService.get_user_role(user_obj) + if not user_role: + return False - # Для CustomUser получаем роль пользователя в текущем тенанте - # ВАЖНО: RoleService работает с текущей tenant schema! - user_role = RoleService.get_user_role(user_obj) - if not user_role: - return False + # Парсим разрешение: 'app_label.action_modelname' + try: + app_label, codename = perm.split('.') + action = codename.split('_')[0] + except (ValueError, IndexError): + return False - # Парсим разрешение: 'app_label.action_modelname' - # Например: 'products.add_product' -> app_label='products', action='add' - try: - app_label, codename = perm.split('.') - # Извлекаем действие из codename (add_product -> add, change_order -> change) - action = codename.split('_')[0] - except (ValueError, IndexError): - return False + # Проверяем, есть ли у роли это разрешение + role_perms = self.ROLE_PERMISSIONS.get(user_role.code, {}) + app_perms = role_perms.get(app_label, []) - # Проверяем, есть ли у роли это разрешение - role_perms = self.ROLE_PERMISSIONS.get(user_role.code, {}) - app_perms = role_perms.get(app_label, []) + return action in app_perms + else: + # Для PlatformAdmin проверяем стандартные permissions через ModelBackend + # Суперпользователь имеет все права + if user_obj.is_superuser: + return True - return action in app_perms + # Проверяем через родительский ModelBackend + return super().has_perm(user_obj, perm, obj) def has_module_perms(self, user_obj, app_label): """ @@ -156,28 +157,32 @@ class RoleBasedPermissionBackend(ModelBackend): if not user_obj.is_authenticated: return False - # Для CustomUser (пользователи тенантов) пропускаем стандартную проверку Django permissions + # Определяем тип пользователя is_tenant = _is_tenant_user(user_obj) - if not is_tenant: - # Для PlatformAdmin проверяем стандартные permissions через ModelBackend - if super().has_module_perms(user_obj, app_label): + # Для CustomUser (пользователи тенантов) НЕ вызываем super().has_module_perms() + if is_tenant: + # Суперпользователь имеет все права + if user_obj.is_superuser: return True - # Суперпользователь имеет все права - if user_obj.is_superuser: - return True + # ВАЖНО: В public схеме нет таблиц UserRole/Role! + if _is_public_schema(): + return False - # ВАЖНО: В public схеме нет таблиц UserRole/Role! - # Используем только стандартные Django permissions. - if _is_public_schema(): - return False + # Для CustomUser получаем роль пользователя в текущем тенанте + user_role = RoleService.get_user_role(user_obj) + if not user_role: + return False - # Для CustomUser получаем роль пользователя в текущем тенанте - user_role = RoleService.get_user_role(user_obj) - if not user_role: - return False + # Проверяем, есть ли у роли какие-либо разрешения для этого приложения + role_perms = self.ROLE_PERMISSIONS.get(user_role.code, {}) + return app_label in role_perms and len(role_perms[app_label]) > 0 + else: + # Для PlatformAdmin проверяем стандартные permissions через ModelBackend + # Суперпользователь имеет все права + if user_obj.is_superuser: + return True - # Проверяем, есть ли у роли какие-либо разрешения для этого приложения - role_perms = self.ROLE_PERMISSIONS.get(user_role.code, {}) - return app_label in role_perms and len(role_perms[app_label]) > 0 + # Проверяем через родительский ModelBackend + return super().has_module_perms(user_obj, app_label)