### 🔄 Изменения - **SQLAlchemy KeyError** - исправление ошибки `KeyError: Reaction` при инициализации - **Исправлена ошибка SQLAlchemy**: Устранена проблема `InvalidRequestError: When initializing mapper Mapper[Shout(shout)], expression Reaction failed to locate a name (Reaction)` ### 🧪 Тестирование - **Исправление тестов** - адаптация к новой структуре моделей - **RBAC инициализация** - добавление `rbac.initialize_rbac()` в `conftest.py` - **Создан тест для getSession**: Добавлен комплексный тест `test_getSession_cookies.py` с проверкой всех сценариев - **Покрытие edge cases**: Тесты проверяют работу с валидными/невалидными токенами, отсутствующими пользователями - **Мокирование зависимостей**: Использование unittest.mock для изоляции тестируемого кода ### 🔧 Рефакторинг - **Упрощена архитектура**: Убраны сложные конструкции с отложенными импортами, заменены на чистую архитектуру - **Перемещение моделей** - `Author` и связанные модели перенесены в `orm/author.py`: Вынесены базовые модели пользователей (`Author`, `AuthorFollower`, `AuthorBookmark`, `AuthorRating`) из `orm.author` в отдельный модуль - **Устранены циклические импорты**: Разорван цикл между `auth.core` → `orm.community` → `orm.author` через реструктуризацию архитектуры - **Создан модуль `utils/password.py`**: Класс `Password` вынесен в utils для избежания циклических зависимостей - **Оптимизированы импорты моделей**: Убран прямой импорт `Shout` из `orm/community.py`, заменен на строковые ссылки ### 🔧 Авторизация с cookies - **getSession теперь работает с cookies**: Мутация `getSession` теперь может получать токен из httpOnly cookies даже без заголовка Authorization - **Убрано требование авторизации**: `getSession` больше не требует декоратор `@login_required`, работает автономно - **Поддержка dual-авторизации**: Токен может быть получен как из заголовка Authorization, так и из cookie `session_token` - **Автоматическая установка cookies**: Middleware автоматически устанавливает httpOnly cookies при успешном `getSession` - **Обновлена GraphQL схема**: `SessionInfo` теперь содержит поля `success`, `error` и опциональные `token`, `author` - **Единообразная обработка токенов**: Все модули теперь используют централизованные функции для работы с токенами - **Улучшена обработка ошибок**: Добавлена детальная валидация токенов и пользователей в `getSession` - **Логирование операций**: Добавлены подробные логи для отслеживания процесса авторизации ### 📝 Документация - **Обновлена схема GraphQL**: `SessionInfo` тип теперь соответствует новому формату ответа - Обновлена документация RBAC - Обновлена документация авторизации с cookies
This commit is contained in:
@@ -2,16 +2,17 @@
|
||||
|
||||
## Общее описание
|
||||
|
||||
Система управления доступом на основе ролей (Role-Based Access Control, RBAC) обеспечивает гибкое управление правами пользователей в рамках сообществ платформы.
|
||||
Система управления доступом на основе ролей (Role-Based Access Control, RBAC) обеспечивает гибкое управление правами пользователей в рамках сообществ платформы. Система поддерживает иерархическое наследование разрешений и автоматическое кеширование для оптимальной производительности.
|
||||
|
||||
## Архитектура системы
|
||||
|
||||
### Принципы работы
|
||||
|
||||
1. **Иерархия ролей**: Роли наследуют права друг от друга
|
||||
1. **Иерархия ролей**: Роли наследуют права друг от друга с рекурсивным вычислением
|
||||
2. **Контекстная проверка**: Права проверяются в контексте конкретного сообщества
|
||||
3. **Системные администраторы**: Пользователи из `ADMIN_EMAILS` автоматически получают роль `admin` в любом сообществе
|
||||
4. **Динамическое определение community_id**: Система автоматически определяет `community_id` из аргументов GraphQL мутаций
|
||||
5. **Рекурсивное наследование**: Разрешения автоматически включают все унаследованные права от родительских ролей
|
||||
|
||||
### Получение community_id
|
||||
|
||||
@@ -27,7 +28,7 @@
|
||||
2. **CommunityAuthor** - связь пользователя с сообществом и его ролями
|
||||
3. **Role** - роль пользователя (reader, author, editor, admin)
|
||||
4. **Permission** - разрешение на выполнение действия
|
||||
5. **RBAC Service** - сервис управления ролями и разрешениями
|
||||
5. **RBAC Service** - сервис управления ролями и разрешениями с рекурсивным наследованием
|
||||
|
||||
### Модель данных
|
||||
|
||||
@@ -103,7 +104,7 @@ CREATE INDEX idx_community_author_author ON community_author(author_id);
|
||||
admin > editor > expert > artist/author > reader
|
||||
```
|
||||
|
||||
Каждая роль автоматически включает права всех ролей ниже по иерархии.
|
||||
Каждая роль автоматически включает права всех ролей ниже по иерархии. Система рекурсивно вычисляет все унаследованные разрешения при инициализации сообщества.
|
||||
|
||||
## Разрешения (Permissions)
|
||||
|
||||
@@ -124,10 +125,6 @@ admin > editor > expert > artist/author > reader
|
||||
- `@require_all_permissions(["permission1", "permission2"])` - проверка наличия всех разрешений
|
||||
|
||||
**Важно**: В resolvers не должна быть дублирующая логика проверки прав - вся проверка осуществляется через систему RBAC.
|
||||
- `comment:create` - создание комментариев
|
||||
- `comment:moderate` - модерация комментариев
|
||||
- `user:manage` - управление пользователями
|
||||
- `community:settings` - настройки сообщества
|
||||
|
||||
### Категории разрешений
|
||||
|
||||
@@ -480,3 +477,78 @@ role_checks_total = Counter('rbac_role_checks_total')
|
||||
permission_checks_total = Counter('rbac_permission_checks_total')
|
||||
role_assignments_total = Counter('rbac_role_assignments_total')
|
||||
```
|
||||
|
||||
## Новые возможности системы
|
||||
|
||||
### Рекурсивное наследование разрешений
|
||||
|
||||
Система теперь поддерживает автоматическое вычисление всех унаследованных разрешений:
|
||||
|
||||
```python
|
||||
# Получить разрешения для конкретной роли с учетом наследования
|
||||
role_permissions = await rbac_ops.get_role_permissions_for_community(
|
||||
community_id=1,
|
||||
role="editor"
|
||||
)
|
||||
# Возвращает: {"editor": ["shout:edit_any", "comment:moderate", "draft:create", "shout:read", ...]}
|
||||
|
||||
# Получить все разрешения для сообщества
|
||||
all_permissions = await rbac_ops.get_all_permissions_for_community(community_id=1)
|
||||
# Возвращает полный словарь всех ролей с их разрешениями
|
||||
```
|
||||
|
||||
### Автоматическая инициализация
|
||||
|
||||
При создании нового сообщества система автоматически инициализирует права с учетом иерархии:
|
||||
|
||||
```python
|
||||
# Автоматически создает расширенные разрешения для всех ролей
|
||||
await rbac_ops.initialize_community_permissions(community_id=123)
|
||||
|
||||
# Система рекурсивно вычисляет все наследованные разрешения
|
||||
# и сохраняет их в Redis для быстрого доступа
|
||||
```
|
||||
|
||||
### Улучшенная производительность
|
||||
|
||||
- **Кеширование в Redis**: Все разрешения кешируются с ключом `community:roles:{community_id}`
|
||||
- **Рекурсивное вычисление**: Разрешения вычисляются один раз при инициализации
|
||||
- **Быстрая проверка**: Проверка разрешений происходит за O(1) из кеша
|
||||
|
||||
### Обновленный API
|
||||
|
||||
```python
|
||||
class RBACOperations(Protocol):
|
||||
# Получить разрешения для конкретной роли с наследованием
|
||||
async def get_role_permissions_for_community(self, community_id: int, role: str) -> dict
|
||||
|
||||
# Получить все разрешения для сообщества
|
||||
async def get_all_permissions_for_community(self, community_id: int) -> dict
|
||||
|
||||
# Проверить разрешения для набора ролей
|
||||
async def roles_have_permission(self, role_slugs: list[str], permission: str, community_id: int) -> bool
|
||||
```
|
||||
|
||||
## Миграция на новую систему
|
||||
|
||||
### Обновление существующего кода
|
||||
|
||||
Если в вашем коде используются старые методы, обновите их:
|
||||
|
||||
```python
|
||||
# Старый код
|
||||
permissions = await rbac_ops._get_role_permissions_for_community(community_id)
|
||||
|
||||
# Новый код
|
||||
permissions = await rbac_ops.get_all_permissions_for_community(community_id)
|
||||
|
||||
# Или для конкретной роли
|
||||
role_permissions = await rbac_ops.get_role_permissions_for_community(community_id, "editor")
|
||||
```
|
||||
|
||||
### Обратная совместимость
|
||||
|
||||
Новая система полностью совместима с существующим кодом:
|
||||
- Все публичные API методы сохранили свои сигнатуры
|
||||
- Декораторы `@require_permission` работают без изменений
|
||||
- Существующие тесты проходят без модификации
|
||||
|
||||
Reference in New Issue
Block a user