Аутентификация и RBAC
JWT-аутентификация
Planner использует JSON Web Token для stateless-аутентификации:
- Access token: время жизни 15 минут, отправляется в заголовке
Authorization: Bearer <token> - Refresh token: время жизни 7 дней, используется для получения новых access токенов
Процесс аутентификации
POST /api/auth/register— создать аккаунт (firstName, lastName, email, password)POST /api/auth/verify-email— подтвердить email по токену из письмаPOST /api/auth/login— получить access + refresh токены (требуется подтверждённый email)- Все последующие запросы включают
Authorization: Bearer <access_token> POST /api/auth/refresh— обменять refresh токен на новый access токенPOST /api/auth/logout— отозвать все refresh токены
Подтверждение email
Новые пользователи должны подтвердить email перед первым входом:
POST /api/auth/register— создаёт пользователя, отправляет письмо с подтверждением (НЕ возвращает токены)POST /api/auth/verify-email— проверяет токен, помечает email как подтверждённыйPOST /api/auth/resend-verification— повторная отправка письма (лимит: 3/мин)POST /api/auth/loginиPOST /api/auth/refresh— возвращаютEMAIL_NOT_VERIFIED, если email не подтверждён- Существующие пользователи получают
emailVerifiedAtчерез seed (prisma/seed.ts)
Ограничение запросов (Rate Limiting)
Защита от brute-force атак:
| Эндпоинт | Лимит |
|---|---|
| Регистрация | 5 запросов/минуту |
| Вход | 10 запросов/минуту |
| Обновление токена | 20 запросов/минуту |
| Забыли пароль | 3 запроса/минуту |
| Сброс пароля | 5 запросов/минуту |
| Подтверждение email | 5 запросов/минуту |
| Повторная отправка | 3 запроса/минуту |
Глобальный лимит: 60 запросов/минуту (хранится в Redis в продакшне).
Блокировка аккаунта
После 5 неудачных попыток входа аккаунт блокируется на 15 минут через Redis (ключ lockout:<email>). Общие сообщения об ошибках (INVALID_CREDENTIALS) предотвращают перебор пользователей.
Требования к паролю
- Минимум 8 символов, максимум 128
- Требуется: заглавная буква, строчная буква, цифра, спецсимвол
- Хешируется bcrypt (cost factor 10)
- Смена пароля инвалидирует все refresh токены
- Сброс пароля также инвалидирует все refresh токены
Ротация refresh токенов
- Refresh токены хранятся как SHA-256 хеш (не в открытом виде)
- При каждом обновлении: старый токен удаляется, выдаётся новый (ротация)
- Обнаружение повторного использования: если ротированный токен предъявлен снова — все токены пользователя удаляются, логируется предупреждение
POST /api/auth/logoutудаляет все refresh токены пользователя
Social Auth
Помимо email/password, поддерживается вход через внешних провайдеров:
| Провайдер | Путь | Описание |
|---|---|---|
| Яндекс ID | /api/auth/social/yandex | Вход через Яндекс |
| VK ID | /api/auth/social/vk | Вход через VK |
Процесс: фронтенд открывает popup-окно на URL провайдера → после успешной аутентификации провайдер редиректит на callback с токенами в URL hash → popup отправляет токены родительскому окну через postMessage → родительское окно закрывает popup и сохраняет токены.
Payload токена
{
"sub": "uuid",
"email": "user@example.com",
"jti": "random-uuid",
"iat": 1234567890,
"exp": 1234568790
}Управление доступом на основе ролей (RBAC)
Система RBAC предоставляет детальные разрешения на нескольких уровнях.
Области разрешений
| Область | Уровень | Пример контроллера |
|---|---|---|
| GLOBAL | Системный | Панель администратора, управление пользователями |
| ORGANIZATION | На организацию | Настройки организации, управление участниками |
| TEAM | На команду | Настройки команды, управление участниками |
| PROJECT | На проект | Настройки проекта, управление задачами |
| TASK | На задачу | CRUD задач (контролируется областью проекта) |
| CHAT | Уровень чата | Управление беседами |
Доступные разрешения (30+)
Организация (org:): create, view, edit, delete, members.view, members.invite, members.remove, members.roles, settings.view, settings.edit
Команда (team:): create, view, edit, delete, members.view, members.add, members.remove, members.roles, settings.view, settings.edit
Проект (project:): create, view, edit, delete, members.view, members.add, members.remove, task.create, task.view, task.edit, task.delete, task.assign, settings.view, settings.edit
Встроенные роли
| Роль | Уровень | Описание |
|---|---|---|
| OWNER | Орг/Команда/Проект | Полный контроль, может удалять |
| ADMIN | Орг/Команда/Проект | Управление пользователями и настройками |
| MANAGER | Орг/Команда/Проект | Операционное управление |
| MEMBER | Орг/Команда/Проект | Базовый доступ |
Пользовательские роли могут быть созданы с любой комбинацией разрешений.
Вычисление разрешений
Разрешения вычисляются из всех ролей пользователя:
effective_permissions = union(
global_roles.permissions,
org_roles.permissions,
team_roles.permissions,
project_roles.permissions
)Проверка разрешений в коде
Бэкенд (NestJS):
@Permissions(['task.create', 'task.edit'])
@Controller('/projects/:projectId/tasks')Фронтенд (Pinia store):
const auth = useAuthStore()
// auth.hasPermission — computed, автоматически разворачивается в шаблоне
if (auth.hasPermission('task.create')) { ... }Группы пользователей
Группы пользователей позволяют массово назначать роли. Создайте группу с набором разрешений, затем добавьте пользователей в группу. Все участники группы наследуют разрешения группы.