Files
core/docs/rbac-system.md

478 lines
17 KiB
Markdown
Raw Normal View History

2025-07-23 13:29:49 +03:00
# Система ролей и разрешений (RBAC)
2025-07-02 22:30:21 +03:00
2025-07-23 13:29:49 +03:00
## Общее описание
2025-07-02 22:30:21 +03:00
2025-07-23 13:29:49 +03:00
Система управления доступом на основе ролей (Role-Based Access Control, RBAC) обеспечивает гибкое управление правами пользователей в рамках сообществ платформы.
2025-07-02 22:30:21 +03:00
2025-07-23 13:29:49 +03:00
## Архитектура системы
2025-07-02 22:30:21 +03:00
2025-07-23 13:29:49 +03:00
### Основные компоненты
2025-07-02 22:30:21 +03:00
2025-07-23 13:29:49 +03:00
1. **Community** - сообщество, контекст для ролей
2. **CommunityAuthor** - связь пользователя с сообществом и его ролями
3. **Role** - роль пользователя (reader, author, editor, admin)
4. **Permission** - разрешение на выполнение действия
5. **RBAC Service** - сервис управления ролями и разрешениями
2025-07-02 22:30:21 +03:00
2025-07-23 13:29:49 +03:00
### Модель данных
2025-07-02 22:30:21 +03:00
```sql
2025-07-23 13:29:49 +03:00
-- Основная таблица связи пользователя с сообществом
2025-07-02 22:30:21 +03:00
CREATE TABLE community_author (
id INTEGER PRIMARY KEY,
2025-07-23 13:29:49 +03:00
community_id INTEGER REFERENCES community(id),
author_id INTEGER REFERENCES author(id),
roles TEXT, -- CSV строка ролей: "reader,author,editor"
joined_at INTEGER NOT NULL,
UNIQUE(community_id, author_id)
2025-07-02 22:30:21 +03:00
);
2025-07-23 13:29:49 +03:00
-- Индексы для производительности
2025-07-02 22:30:21 +03:00
CREATE INDEX idx_community_author_community ON community_author(community_id);
CREATE INDEX idx_community_author_author ON community_author(author_id);
```
2025-07-23 13:29:49 +03:00
## Роли в системе
### Базовые роли
#### 1. `reader` (Читатель)
- **Обязательная роль для всех пользователей**
- **Права:**
- Чтение публикаций
- Просмотр комментариев
- Подписка на сообщества
- Базовая навигация по платформе
#### 2. `author` (Автор)
- **Права:**
- Все права `reader`
- Создание публикаций (шаутов)
- Редактирование своих публикаций
- Комментирование
- Создание черновиков
#### 3. `artist` (Художник)
- **Права:**
- Все права `author`
- Может быть указан как credited artist
- Загрузка и управление медиафайлами
#### 4. `expert` (Эксперт)
- **Права:**
- Все права `author`
- Добавление доказательств (evidence)
- Верификация контента
- Экспертная оценка публикаций
#### 5. `editor` (Редактор)
- **Права:**
- Все права `expert`
- Модерация контента
- Редактирование чужих публикаций
- Управление тегами и категориями
- Модерация комментариев
#### 6. `admin` (Администратор)
- **Права:**
- Все права `editor`
- Управление пользователями
- Управление ролями
- Настройка сообщества
- Полный доступ к административной панели
2025-07-02 22:30:21 +03:00
2025-07-23 13:29:49 +03:00
### Иерархия ролей
```
admin > editor > expert > artist/author > reader
```
Каждая роль автоматически включает права всех ролей ниже по иерархии.
## Разрешения (Permissions)
### Формат разрешений
Разрешения записываются в формате `resource:action`:
- `shout:create` - создание публикаций
- `shout:edit` - редактирование публикаций
- `shout:delete` - удаление публикаций
- `comment:create` - создание комментариев
- `comment:moderate` - модерация комментариев
- `user:manage` - управление пользователями
- `community:settings` - настройки сообщества
### Категории разрешений
#### Контент (Content)
- `shout:create` - создание шаутов
- `shout:edit_own` - редактирование своих шаутов
- `shout:edit_any` - редактирование любых шаутов
- `shout:delete_own` - удаление своих шаутов
- `shout:delete_any` - удаление любых шаутов
- `shout:publish` - публикация шаутов
- `shout:feature` - продвижение шаутов
#### Комментарии (Comments)
- `comment:create` - создание комментариев
- `comment:edit_own` - редактирование своих комментариев
- `comment:edit_any` - редактирование любых комментариев
- `comment:delete_own` - удаление своих комментариев
- `comment:delete_any` - удаление любых комментариев
- `comment:moderate` - модерация комментариев
#### Пользователи (Users)
- `user:view_profile` - просмотр профилей
- `user:edit_own_profile` - редактирование своего профиля
- `user:manage_roles` - управление ролями пользователей
- `user:ban` - блокировка пользователей
#### Сообщество (Community)
- `community:view` - просмотр сообщества
- `community:settings` - настройки сообщества
- `community:manage_members` - управление участниками
- `community:analytics` - просмотр аналитики
## Логика работы системы
### 1. Регистрация пользователя
При регистрации пользователя:
2025-07-02 22:30:21 +03:00
```python
2025-07-23 13:29:49 +03:00
# 1. Создается запись в Author
user = Author(email=email, name=name, ...)
# 2. Создается связь с дефолтным сообществом (ID=1)
community_author = CommunityAuthor(
community_id=1,
author_id=user.id,
roles="reader,author" # Дефолтные роли
)
2025-07-02 22:30:21 +03:00
2025-07-23 13:29:49 +03:00
# 3. Создается подписка на сообщество
follower = CommunityFollower(
community=1,
follower=user.id
)
```
2025-07-02 22:30:21 +03:00
2025-07-23 13:29:49 +03:00
### 2. Проверка авторизации
2025-07-02 22:30:21 +03:00
2025-07-23 13:29:49 +03:00
При входе в систему проверяется наличие роли `reader`:
2025-07-02 22:30:21 +03:00
2025-07-23 13:29:49 +03:00
```python
def login(email, password):
# 1. Найти пользователя
author = Author.get_by_email(email)
2025-07-02 22:30:21 +03:00
2025-07-23 13:29:49 +03:00
# 2. Проверить пароль
if not verify_password(password, author.password):
return error("Неверный пароль")
2025-07-02 22:30:21 +03:00
2025-07-23 13:29:49 +03:00
# 3. Получить роли в дефолтном сообществе
user_roles = get_user_roles_in_community(author.id, community_id=1)
2025-07-02 22:30:21 +03:00
2025-07-23 13:29:49 +03:00
# 4. Проверить наличие роли reader
if "reader" not in user_roles and author.email not in ADMIN_EMAILS:
return error("Нет прав для входа. Требуется роль 'reader'.")
2025-07-02 22:30:21 +03:00
2025-07-23 13:29:49 +03:00
# 5. Создать сессию
return create_session(author)
2025-07-02 22:30:21 +03:00
```
2025-07-23 13:29:49 +03:00
### 3. Проверка разрешений
При выполнении действий проверяются разрешения:
2025-07-02 22:30:21 +03:00
```python
2025-07-23 13:29:49 +03:00
@login_required
async def create_shout(info, input):
user_id = info.context["author"]["id"]
# Проверяем разрешение на создание шаутов
has_permission = await check_user_permission_in_community(
user_id,
"shout:create",
community_id=1
)
if not has_permission:
raise GraphQLError("Недостаточно прав для создания публикации")
# Создаем шаут
return Shout.create(input)
```
2025-07-02 22:30:21 +03:00
2025-07-23 13:29:49 +03:00
### 4. Управление ролями
2025-07-02 22:30:21 +03:00
2025-07-23 13:29:49 +03:00
#### Назначение ролей
2025-07-02 22:30:21 +03:00
2025-07-23 13:29:49 +03:00
```python
# Назначить роль пользователю
assign_role_to_user(user_id=123, role="editor", community_id=1)
# Убрать роль
remove_role_from_user(user_id=123, role="editor", community_id=1)
# Установить все роли
community.set_user_roles(user_id=123, roles=["reader", "author", "editor"])
```
#### Проверка ролей
```python
# Получить роли пользователя
roles = get_user_roles_in_community(user_id=123, community_id=1)
2025-07-02 22:30:21 +03:00
2025-07-23 13:29:49 +03:00
# Проверить конкретную роль
has_role = "editor" in roles
# Проверить разрешение
has_permission = await check_user_permission_in_community(
user_id=123,
permission="shout:edit_any",
2025-07-02 22:30:21 +03:00
community_id=1
)
2025-07-23 13:29:49 +03:00
```
2025-07-02 22:30:21 +03:00
2025-07-23 13:29:49 +03:00
## Конфигурация сообщества
2025-07-02 22:30:21 +03:00
2025-07-23 13:29:49 +03:00
### Дефолтные роли
2025-07-02 22:30:21 +03:00
2025-07-23 13:29:49 +03:00
Каждое сообщество может настроить свои дефолтные роли для новых пользователей:
2025-07-02 22:30:21 +03:00
2025-07-23 13:29:49 +03:00
```python
# Получить дефолтные роли
default_roles = community.get_default_roles() # ["reader", "author"]
# Установить дефолтные роли
community.set_default_roles(["reader"]) # Только reader по умолчанию
2025-07-02 22:30:21 +03:00
```
2025-07-23 13:29:49 +03:00
### Доступные роли
Сообщество может ограничить список доступных ролей:
```python
# Все роли доступны по умолчанию
available_roles = ["reader", "author", "artist", "expert", "editor", "admin"]
# Ограничить только базовыми ролями
community.set_available_roles(["reader", "author", "editor"])
2025-07-02 22:30:21 +03:00
```
2025-07-23 13:29:49 +03:00
## Миграция данных
2025-07-02 22:30:21 +03:00
2025-07-23 13:29:49 +03:00
### Проблемы существующих пользователей
2025-07-02 22:30:21 +03:00
2025-07-23 13:29:49 +03:00
1. **Пользователи без роли `reader`** - не могут войти в систему
2. **Старая система ролей** - данные в `Author.roles` устарели
3. **Отсутствие связей `CommunityAuthor`** - новые пользователи без ролей
2025-07-02 22:30:21 +03:00
2025-07-23 13:29:49 +03:00
### Решения
2025-07-02 22:30:21 +03:00
2025-07-23 13:29:49 +03:00
#### 1. Автоматическое добавление роли `reader`
2025-07-03 12:15:10 +03:00
2025-07-23 13:29:49 +03:00
```python
async def ensure_user_has_reader_role(user_id: int) -> bool:
"""Убеждается, что у пользователя есть роль 'reader'"""
existing_roles = get_user_roles_in_community(user_id, community_id=1)
if "reader" not in existing_roles:
success = assign_role_to_user(user_id, "reader", community_id=1)
if success:
logger.info(f"Роль 'reader' добавлена пользователю {user_id}")
return True
return True
```
2025-07-02 22:30:21 +03:00
2025-07-23 13:29:49 +03:00
#### 2. Массовое исправление ролей
```python
async def fix_all_users_reader_role() -> dict[str, int]:
"""Проверяет всех пользователей и добавляет роль 'reader'"""
stats = {"checked": 0, "fixed": 0, "errors": 0}
all_authors = session.query(Author).all()
for author in all_authors:
stats["checked"] += 1
try:
await ensure_user_has_reader_role(author.id)
stats["fixed"] += 1
except Exception as e:
logger.error(f"Ошибка для пользователя {author.id}: {e}")
stats["errors"] += 1
return stats
```
#### 3. Миграция из старой системы
```python
def migrate_old_roles_to_community_author():
"""Переносит роли из старой системы в CommunityAuthor"""
# Получаем все старые роли из Author.roles
old_roles = session.query(AuthorRole).all()
for role in old_roles:
# Создаем запись CommunityAuthor
ca = CommunityAuthor(
community_id=role.community,
author_id=role.author,
roles=role.role
)
session.add(ca)
session.commit()
```
## API для работы с ролями
### GraphQL мутации
2025-07-02 22:30:21 +03:00
```graphql
2025-07-23 13:29:49 +03:00
# Назначить роль пользователю
mutation AssignRole($userId: Int!, $role: String!, $communityId: Int) {
assignRole(userId: $userId, role: $role, communityId: $communityId) {
2025-07-02 22:30:21 +03:00
success
2025-07-23 13:29:49 +03:00
message
2025-07-02 22:30:21 +03:00
}
}
2025-07-23 13:29:49 +03:00
# Убрать роль
mutation RemoveRole($userId: Int!, $role: String!, $communityId: Int) {
removeRole(userId: $userId, role: $role, communityId: $communityId) {
success
message
}
}
2025-07-02 22:30:21 +03:00
2025-07-23 13:29:49 +03:00
# Установить все роли пользователя
mutation SetUserRoles($userId: Int!, $roles: [String!]!, $communityId: Int) {
setUserRoles(userId: $userId, roles: $roles, communityId: $communityId) {
2025-07-02 22:30:21 +03:00
success
2025-07-23 13:29:49 +03:00
message
2025-07-02 22:30:21 +03:00
}
}
```
2025-07-23 13:29:49 +03:00
### GraphQL запросы
2025-07-02 22:30:21 +03:00
```graphql
2025-07-23 13:29:49 +03:00
# Получить роли пользователя
query GetUserRoles($userId: Int!, $communityId: Int) {
userRoles(userId: $userId, communityId: $communityId) {
roles
permissions
community {
id
name
}
}
}
# Получить всех участников сообщества с ролями
query GetCommunityMembers($communityId: Int!) {
communityMembers(communityId: $communityId) {
authorId
roles
permissions
joinedAt
author {
id
name
email
}
2025-07-02 22:30:21 +03:00
}
}
```
2025-07-23 13:29:49 +03:00
## Безопасность
2025-07-02 22:30:21 +03:00
2025-07-23 13:29:49 +03:00
### Принципы безопасности
2025-07-02 22:30:21 +03:00
2025-07-23 13:29:49 +03:00
1. **Принцип минимальных привилегий** - пользователь получает только необходимые права
2. **Разделение обязанностей** - разные роли для разных функций
3. **Аудит действий** - логирование всех изменений ролей
4. **Проверка на каждом уровне** - валидация разрешений в API и UI
2025-07-02 22:30:21 +03:00
2025-07-23 13:29:49 +03:00
### Защита от атак
2025-07-02 22:30:21 +03:00
2025-07-23 13:29:49 +03:00
1. **Privilege Escalation** - проверка прав на изменение ролей
2. **Mass Assignment** - валидация входных данных
3. **CSRF** - использование токенов для изменения ролей
4. **XSS** - экранирование данных ролей в UI
2025-07-02 22:30:21 +03:00
2025-07-23 13:29:49 +03:00
### Логирование
2025-07-02 22:30:21 +03:00
```python
2025-07-23 13:29:49 +03:00
# Логирование изменений ролей
logger.info(f"Role {role} assigned to user {user_id} by admin {admin_id}")
logger.warning(f"Failed login attempt for user without reader role: {user_id}")
logger.error(f"Permission denied: user {user_id} tried to access {resource}")
2025-07-02 22:30:21 +03:00
```
2025-07-23 13:29:49 +03:00
## Тестирование
2025-07-02 22:30:21 +03:00
2025-07-23 13:29:49 +03:00
### Тестовые сценарии
2025-07-02 22:30:21 +03:00
2025-07-23 13:29:49 +03:00
1. **Регистрация пользователя** - проверка назначения дефолтных ролей
2. **Вход в систему** - проверка требования роли `reader`
3. **Назначение ролей** - проверка прав администратора
4. **Проверка разрешений** - валидация доступа к ресурсам
5. **Иерархия ролей** - наследование прав
2025-07-02 22:30:21 +03:00
2025-07-23 13:29:49 +03:00
### Пример тестов
2025-07-02 22:30:21 +03:00
2025-07-23 13:29:49 +03:00
```python
def test_user_registration_assigns_default_roles():
"""Проверяет назначение дефолтных ролей при регистрации"""
user = create_user(email="test@test.com")
roles = get_user_roles_in_community(user.id, community_id=1)
2025-07-02 22:30:21 +03:00
2025-07-23 13:29:49 +03:00
assert "reader" in roles
assert "author" in roles
2025-07-02 22:30:21 +03:00
2025-07-23 13:29:49 +03:00
def test_login_requires_reader_role():
"""Проверяет требование роли reader для входа"""
user = create_user_without_roles(email="test@test.com")
2025-07-02 22:30:21 +03:00
2025-07-23 13:29:49 +03:00
result = login(email="test@test.com", password="password")
2025-07-02 22:30:21 +03:00
2025-07-23 13:29:49 +03:00
assert result["success"] == False
assert "reader" in result["error"]
2025-07-02 22:30:21 +03:00
2025-07-23 13:29:49 +03:00
def test_role_hierarchy():
"""Проверяет иерархию ролей"""
user = create_user(email="admin@test.com")
assign_role_to_user(user.id, "admin", community_id=1)
2025-07-02 22:30:21 +03:00
2025-07-23 13:29:49 +03:00
# Админ должен иметь все права
assert check_permission(user.id, "shout:create")
assert check_permission(user.id, "user:manage")
assert check_permission(user.id, "community:settings")
2025-07-02 22:30:21 +03:00
```
2025-07-23 13:29:49 +03:00
## Производительность
2025-07-02 22:30:21 +03:00
2025-07-23 13:29:49 +03:00
### Оптимизации
2025-07-02 22:30:21 +03:00
2025-07-23 13:29:49 +03:00
1. **Кеширование ролей** - хранение ролей пользователя в Redis
2. **Индексы БД** - быстрый поиск по `community_id` и `author_id`
3. **Batch операции** - массовое назначение ролей
4. **Ленивая загрузка** - загрузка разрешений по требованию
2025-07-02 22:30:21 +03:00
2025-07-23 13:29:49 +03:00
### Мониторинг
2025-07-02 22:30:21 +03:00
2025-07-23 13:29:49 +03:00
```python
# Метрики для Prometheus
role_checks_total = Counter('rbac_role_checks_total')
permission_checks_total = Counter('rbac_permission_checks_total')
role_assignments_total = Counter('rbac_role_assignments_total')
2025-07-02 22:30:21 +03:00
```