# Лабараторная 2 Минимальный костяк сервиса управления пользователями и OAuth-клиентами. Предоставляет REST API по пути `/auth/*`, GraphQL-эндпоинт по адресу `/graphql` и небольшое админ-SPA на чистом JS, отдаваемое по `/admin`. Основные технологии: - Python 3.12 - **FastAPI** - REST API (`/auth/register`, `/auth/login`, `/auth/me`) - **Ariadne** - GraphQL-сервер - **SQLAlchemy 2.x** - ORM - **Alembic** - миграции - **SQLite** - база данных - **argon2-cffi** - хеширование паролей Argon2id + стойкость через `zxcvbn` - **python-jose** - JWT токены ## Установка ```sh git clone https://vantablacktea.ddns.net/Agzamus/scripts-2.git cd scripts-2 ``` ### С помощью uv [Скачать uv](https://docs.astral.sh/uv/) ```sh uv sync uv run python run.py ``` Тесты: ```sh uv run pytest -q ``` ### Альтернатива с pip Linux: ```sh python -m venv .venv source .venv/bin/activate pip install -r requirements.txt ``` Windows: ```sh python -m venv .venv source .venv\Scripts\activate pip install -r requirements.txt ``` ## Настройка Необходимо создать `.env` файл, например скопировав пример: ```sh cp .env.example .env ``` > Записать для `JWT_SECRET` и `PASSWORD_PEPPER` длинные случайные строки > `JWT_SECRET` подписывает каждый access-токен, а `PASSWORD_PEPPER` добавляется к паролю перед хешированием Переменные из `.env.example`: | Переменная | Пример | Назначение | | ---------------------- | ----------------------------------------- | ------------------------------------------------- | | `DATABASE_URL` | `sqlite:///./vault.db` | Строка подключения SQLAlchemy | | `JWT_SECRET` | `replace_with_a_long_random_string` | Секрет для подписи/проверки JWT | | `JWT_ALGORITHM` | `HS256` | Алгоритм подписи JWT | | `ACCESS_TOKEN_TTL_MIN` | `60` | Время жизни access-токена в минутах | | `PASSWORD_PEPPER` | `replace_with_another_long_random_string` | Глобальный секрет, добавляемый перед хешированием | | `PASSWORD_MIN_LENGTH` | `12` | Минимальная длина пароля | | `ENVIRONMENT` | `development` | Метка окружения выполнения | | `APP_NAME` | `Vault` | Заголовок приложения | ## Запуск Примените миграции базы данных, затем запустите сервер: ```bash uv run alembic upgrade head # создать/обновить схему базы данных uv run python run.py # uvicorn на 0.0.0.0:8000 с reload ``` Или напрямую: ```bash uv run uvicorn app.main:app --reload ``` После запуска: - GraphQL Playground: - Admin UI: ### Заполнение демо-данными ##### Администратор Может открыть админ-панель Почта: ``` admin@example.com ``` Пароль: ``` Kz8#Fj2!Lm9@Qw4$xR ``` ##### Пользователь ``` user@example.com ``` ``` DemoUser-Pass#2024 ``` ##### OAuth-клиент `demo-client` - "Demo App" ``` redirect_uris = ["https://example.com/callback"] ``` #### Заполнение: Убедитесь, что схема создана (запустите один раз или при каждом изменении миграций): ```bash uv run alembic upgrade head ``` Запустите скрипт заполнения: ```bash uv run python seed.py ``` Запустите сервер: ```bash uv run python run.py ``` Админ панель: #### Свои учётные данные Переопределите значения по умолчанию через переменные окружения, например: ```bash SEED_ADMIN_EMAIL=root@corp.io \ SEED_ADMIN_PASSWORD='S0me-very-Long-Random-Passphrase!42' \ uv run python seed.py ``` | Переменная | Значение по умолчанию | | --------------------- | --------------------- | | `SEED_ADMIN_EMAIL` | `admin@example.com` | | `SEED_ADMIN_PASSWORD` | `Kz8#Fj2!Lm9@Qw4$xR` | | `SEED_USER_EMAIL` | `user@example.com` | | `SEED_USER_PASSWORD` | `DemoUser-Pass#2024` | > Пароли из seed-скрипта обходят политику стойкости при регистрации #### Сброс Чтобы сбросить базу данных: ```sh rm -f vault.db uv run alembic upgrade head uv run python seed.py ``` ## Структура проекта ``` . ├── alembic/ # окружение миграций Alembic ├── alembic.ini # конфигурация Alembic ├── app/ │ ├── main.py # FastAPI приложение │ ├── config.py # настройки из .env │ ├── db/ # движок, SessionLocal, get_db() и декларативная Base │ ├── models/ # модели SQLAlchemy: User, OAuthClient, AuditEvent │ ├── core/ # JWT, хеширование паролей, зависимости аутентификации │ ├── auth/ # REST и схемы Pydantic │ ├── audit/ # запись событий в базу данных │ ├── graphql/ # схема Ariadne, резолверы, контекст и директивы │ │ └── schema.graphql # SDL GraphQL │ └── static/ # Фронт ├── tests/ # тесты Pytest ├── run.py # точка входа Uvicorn ├── seed.py # заполнение демо-данными ├── pyproject.toml # метаданные проекта и зависимости (uv) └── requirements.txt # зафиксированные зависимости для установки через pip ``` ## Пример GraphQL Передайте JWT как bearer-токен: ```sh curl http://localhost:8000/graphql/ \ -H 'Content-Type: application/json' \ -H 'Authorization: Bearer ' \ -d '{"query": "{ me { email } }"}' ``` Тело запроса: ```graphql { me { email } } ``` Пример ответа: ```json { "data": { "me": { "email": "user@example.com" } } } ``` ## Тестирование ```bash uv run pytest -q ``` ## Примечания `.env` и `*.db` не коммитятся - они перечислены в `.gitignore` вместе с `__pycache__/`, `.venv/` и другими локальными артефактами Держите секреты и локальные базы данных вне системы контроля версий