Files
auth-project/readme.md
2026-07-12 22:06:20 +03:00

151 lines
9.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Auth & Authorization Service
Backend-приложение на **FastAPI + SQLAlchemy**, реализующее собственную систему
аутентификации и авторизации без использования готовых auth-механизмов фреймворка.
## Стек
- **FastAPI** — веб-фреймворк, роутинг, dependency injection
- **SQLAlchemy (ORM)** — доступ к БД, `sessionmaker`, декларативные модели
- **python-jose (jwt)** — создание и валидация JWT-токенов
- **bcrypt / passlib** — хеширование паролей
- **Pydantic v2** — схемы валидации запросов/ответов
- **Alembic** - Миграции бд
## Аутентификация
Аутентификация построена на **JWT-токенах** (Bearer), без серверных сессий.
1. Клиент отправляет `POST /protected/token` с `email` (как `username`) и `password`
в формате `OAuth2PasswordRequestForm` (form-data).
2. Сервер ищет пользователя по email, сверяет пароль через bcrypt
(`hash_check(plain, hashed)`).
3. Если пара email/пароль верна — выпускается JWT с payload `{"sub": <user.id>}`,
подписанный секретным ключом (`ENV.SECRET_STRING`, алгоритм `ENV.ALGORITHM`).
4. Клиент передаёт токен в заголовке `Authorization: Bearer <token>` в каждом
последующем запросе.
5. На защищённых эндпоинтах зависимость `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) | отчество |
| email | 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/ # тесты (Пусто, не создавались)
```
## Запуск
```bash
poetry
make run
```
Переименовать env