Рабочие изменения: улучшения UI, настройки и бэкенд авторизации
Собрал накопившиеся изменения из рабочей директории: UI улучшения: - customer_detail.html: Расширен интерфейс детальной страницы клиента - order_detail.html: Добавлены элементы отображения деталей заказа - order_list.html: Улучшена визуализация списка заказов Бэкенд: - customers/views.py: Доработаны представления для работы с клиентами - products/views/product_views.py: Минорные правки - user_roles/auth_backend.py: Добавлен кастомный бэкенд авторизации Настройки: - myproject/settings.py: Обновлены конфигурации - .gitignore: Добавлен для игнорирования служебных файлов - requirements.txt: Удален (вероятно заменен на poetry/pipenv) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
142
myproject/user_roles/auth_backend.py
Normal file
142
myproject/user_roles/auth_backend.py
Normal file
@@ -0,0 +1,142 @@
|
||||
"""
|
||||
Кастомный backend аутентификации для связывания ролей с Django permissions API.
|
||||
|
||||
ВАЖНО: Этот backend НЕ использует таблицы Django permissions из public schema!
|
||||
Он только эмулирует API has_perm(), читая роли из текущей tenant schema.
|
||||
Это безопасно для мультитенантной архитектуры.
|
||||
"""
|
||||
from django.contrib.auth.backends import ModelBackend
|
||||
from user_roles.services import RoleService
|
||||
from user_roles.models import Role
|
||||
|
||||
|
||||
class RoleBasedPermissionBackend(ModelBackend):
|
||||
"""
|
||||
Backend, который предоставляет права на основе роли пользователя в текущем тенанте.
|
||||
|
||||
Расширяет стандартный ModelBackend, добавляя проверку прав на основе ролей из tenant schema.
|
||||
|
||||
Как это работает:
|
||||
1. Django вызывает user.has_perm('products.add_product')
|
||||
2. Backend проверяет роль пользователя в ТЕКУЩЕЙ tenant schema (через RoleService)
|
||||
3. На основе роли возвращает True/False
|
||||
4. Никакие данные из public schema не используются!
|
||||
"""
|
||||
|
||||
# Маппинг ролей на наборы разрешений
|
||||
# Формат: 'app_label': ['action1', 'action2', ...]
|
||||
# где action - это префикс permission: add_product -> add, change_order -> change
|
||||
ROLE_PERMISSIONS = {
|
||||
Role.OWNER: {
|
||||
# Владелец: полный доступ ко всем модулям
|
||||
'products': ['add', 'change', 'delete', 'view'],
|
||||
'inventory': ['add', 'change', 'delete', 'view'],
|
||||
'orders': ['add', 'change', 'delete', 'view'],
|
||||
'clients': ['add', 'change', 'delete', 'view'],
|
||||
'suppliers': ['add', 'change', 'delete', 'view'],
|
||||
'user_roles': ['add', 'change', 'delete', 'view'],
|
||||
'payments': ['add', 'change', 'delete', 'view'],
|
||||
},
|
||||
Role.MANAGER: {
|
||||
# Менеджер: доступ к основным операционным модулям (без настроек)
|
||||
'products': ['add', 'change', 'delete', 'view'],
|
||||
'inventory': ['add', 'change', 'delete', 'view'],
|
||||
'orders': ['add', 'change', 'delete', 'view'],
|
||||
'clients': ['add', 'change', 'delete', 'view'],
|
||||
'suppliers': ['add', 'change', 'view'], # только просмотр и изменение, без удаления
|
||||
'payments': ['view'],
|
||||
},
|
||||
Role.FLORIST: {
|
||||
# Флорист: работа с заказами и просмотр товаров
|
||||
'products': ['view'],
|
||||
'inventory': ['view', 'change'], # может обновлять остатки при сборке заказов
|
||||
'orders': ['change', 'view'],
|
||||
},
|
||||
Role.COURIER: {
|
||||
# Курьер: только просмотр и обновление статуса заказов
|
||||
'orders': ['change', 'view'],
|
||||
},
|
||||
}
|
||||
|
||||
def has_perm(self, user_obj, perm, obj=None):
|
||||
"""
|
||||
Проверяет, имеет ли пользователь указанное разрешение.
|
||||
|
||||
Формат разрешения: 'app_label.action_modelname'
|
||||
Например: 'products.add_product', 'orders.change_order'
|
||||
|
||||
Args:
|
||||
user_obj: Пользователь
|
||||
perm: Строка разрешения в формате 'app.action_model'
|
||||
obj: Опциональный объект для object-level permissions
|
||||
|
||||
Returns:
|
||||
bool: True если пользователь имеет разрешение
|
||||
"""
|
||||
# Сначала проверяем стандартные permissions через ModelBackend
|
||||
# (для superuser, staff с Django permissions и т.д.)
|
||||
if super().has_perm(user_obj, perm, obj):
|
||||
return True
|
||||
|
||||
# Если пользователь не аутентифицирован, нет доступа
|
||||
if not user_obj.is_authenticated:
|
||||
return False
|
||||
|
||||
# Суперпользователь имеет все права
|
||||
if user_obj.is_superuser:
|
||||
return True
|
||||
|
||||
# Получаем роль пользователя в текущем тенанте
|
||||
# ВАЖНО: RoleService работает с текущей tenant schema!
|
||||
user_role = RoleService.get_user_role(user_obj)
|
||||
if not user_role:
|
||||
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, [])
|
||||
|
||||
return action in app_perms
|
||||
|
||||
def has_module_perms(self, user_obj, app_label):
|
||||
"""
|
||||
Проверяет, имеет ли пользователь какие-либо разрешения для приложения.
|
||||
|
||||
Используется в Django admin для определения, показывать ли модуль в навигации.
|
||||
|
||||
Args:
|
||||
user_obj: Пользователь
|
||||
app_label: Название приложения (например, 'products', 'orders')
|
||||
|
||||
Returns:
|
||||
bool: True если пользователь имеет хотя бы одно разрешение для приложения
|
||||
"""
|
||||
# Сначала проверяем стандартные permissions через ModelBackend
|
||||
if super().has_module_perms(user_obj, app_label):
|
||||
return True
|
||||
|
||||
# Если пользователь не аутентифицирован, нет доступа
|
||||
if not user_obj.is_authenticated:
|
||||
return False
|
||||
|
||||
# Суперпользователь имеет все права
|
||||
if user_obj.is_superuser:
|
||||
return True
|
||||
|
||||
# Получаем роль пользователя в текущем тенанте
|
||||
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
|
||||
Reference in New Issue
Block a user