Auth & Authorization Service
Backend-приложение на FastAPI + SQLAlchemy, реализующее собственную систему аутентификации и авторизации без использования готовых auth-механизмов фреймворка.
Стек
- FastAPI — веб-фреймворк, роутинг, dependency injection
- SQLAlchemy (ORM) — доступ к БД,
sessionmaker, декларативные модели - python-jose (jwt) — создание и валидация JWT-токенов
- bcrypt / passlib — хеширование паролей
- Pydantic v2 — схемы валидации запросов/ответов
- Alembic - Миграции бд
Аутентификация
Аутентификация построена на JWT-токенах (Bearer), без серверных сессий.
- Клиент отправляет
POST /protected/tokenсemail(какusername) иpasswordв форматеOAuth2PasswordRequestForm(form-data). - Сервер ищет пользователя по email, сверяет пароль через bcrypt
(
hash_check(plain, hashed)). - Если пара email/пароль верна — выпускается JWT с payload
{"sub": <user.id>}, подписанный секретным ключом (ENV.SECRET_STRING, алгоритмENV.ALGORITHM). - Клиент передаёт токен в заголовке
Authorization: Bearer <token>в каждом последующем запросе. - На защищённых эндпоинтах зависимость
get_current_user:- декодирует токен (
jwt.decode), - достаёт
sub(id пользователя), - загружает пользователя из БД вместе с его правами,
- при любой ошибке (невалидный/просроченный токен, юзер не найден) — 401 Unauthorized.
- декодирует токен (
logout в чистой JWT-схеме требует либо короткого TTL токена + refresh-токена, либо чёрного списка отозванных токенов (таблица
revoked_tokens). Также можно просто затирать токен на фронтенде при разлогине, как самый простой вариант.
Модель авторизации
Вместо классической схемы roles / business_elements / access_roles_rules
(с раздельными read/create/update/delete × _all) выбрана более простая
flat-модель прав доступа, которая проще для демонстрации, но покрывает те же
принципы: пользователь получает набор строковых прав (permissions), и каждый
эндпоинт объявляет, какие права требуются для его вызова.
Таблицы БД
users
| поле | тип | описание |
|---|---|---|
| id | int, PK | идентификатор пользователя |
| name | str(64) | имя |
| last_name | str(64) | фамилия |
| middle_name | str(64) | отчество |
| str(255) | email, unique | |
| status | bool | активен ли аккаунт (используется вместо is_active для мягкого удаления) |
| hashed_password | str(255) | bcrypt-хеш пароля |
permissions
| поле | тип | описание |
|---|---|---|
| id | int, PK | идентификатор права |
| permission | str(64) | код права: admin, can_view, can_create, can_edit, can_delete |
user_permission (association table, many-to-many)
| поле | тип | описание |
|---|---|---|
| user_id | FK | → users.id |
| permission_id | FK | → permissions.id |
Один пользователь может иметь несколько прав одновременно (например,
can_view + can_edit); право admin даёт полный доступ и разрешает
выдавать/забирать любые права, включая admin, другим пользователям.
Правила проверки доступа
Каждый метод бизнес-логики (CrudActions) явно объявляет множество
допустимых прав и проверяет его перед выполнением действия:
| Действие | Требуемое право |
|---|---|
| Просмотр пользователя (по email/id) | can_view или admin |
| Создание пользователя | can_create или admin |
| Изменение пользователя | can_edit или admin |
| Удаление пользователя | can_delete или admin |
Дополнительно действует правило защиты от эскалации привилегий: пользователь
без права admin не может назначить право admin ни себе, ни другому
пользователю при создании/редактировании аккаунта.
Обработка ошибок доступа
- 401 Unauthorized — если запрос не удаётся сопоставить с валидным залогиненным пользователем (нет токена, токен просрочен/невалиден, юзер из токена не существует).
- 403 Forbidden — пользователь определён, но у него нет нужного права на запрошенное действие/ресурс (в т.ч. попытка эскалации прав, попытка занять чужой email).
- 404 Not Found — запрошенный ресурс (пользователь, право) не существует.
API
| Метод | Путь | Требуемое право | Описание |
|---|---|---|---|
| POST | /protected/token |
— | Логин, выдача JWT |
| POST | /protected/logout |
— | Логин, выдача JWT |
| GET | /protected/get_user_by_email |
can_view / admin |
Получить пользователя по email |
| GET | /protected/get_user_by_id |
can_view / admin |
Получить пользователя по id |
| POST | /protected/create_user |
can_create / admin |
Создать пользователя |
| PATCH | /protected/update_user |
can_edit / admin |
Обновить свой профиль или (для admin/can_edit) чужой через target_id |
| DELETE | /protected/delete_user |
can_delete / admin |
Удалить (деактивировать) пользователя |
Тестовые данные
Для демонстрации системы в БД должны быть заведены минимум: Пароли d@d.d, d1@d.d, d2@d.d 12345678
- 1 пользователь с правом
admin(полный доступ) - 1 пользователь с правом
can_view(только просмотр) - 1 пользователь без прав (для проверки 403)
Структура проекта
src/
db/ # ActionsDB — доступ к БД (SQLAlchemy sessions, запросы)
model/
database_model/ # SQLAlchemy-модели (User, Permissions)
user/ # Pydantic-схемы (UserOut, UserCreate, UserUpdate, PermissionIn/Out)
env_read/ # Чтение env через pydantic settings
service/
crud_actions/ # CrudActions — бизнес-логика + проверки прав доступа
JWT/ # JWT (кодирование/декодирование токена), Hash (bcrypt)
auth/ # Создание и проверка jwt токена
errors/ # централизованные HTTP-ошибки (401/403/404)
web/ # роутеры FastAPI (эндпоинты)
migrations/ # миграции бд
tests/ # тесты (Пусто, не создавались)
Запуск
poetry
make run
Переименовать env