Files
scripts-2/README.md
T
2026-10-12 19:48:57 +03:00

270 lines
9.4 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.
# Лабараторная 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: <http://localhost:8000/graphql>
- Admin UI: <http://localhost:8000/admin>
### Заполнение демо-данными
##### Администратор
Может открыть админ-панель
Почта:
```
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
```
Админ панель: <http://localhost:8000/admin>
#### Свои учётные данные
Переопределите значения по умолчанию через переменные окружения, например:
```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
```
<!-- ## Обзор API -->
<!---->
<!-- ### REST (`/auth`) -->
<!---->
<!-- | Метод | Путь | Аутентификация | Описание | -->
<!-- | --- | --- | --- | --- | -->
<!-- | `POST` | `/auth/register` | нет | Зарегистрировать нового пользователя; возвращает access-токен | -->
<!-- | `POST` | `/auth/login` | нет | Аутентифицировать и вернуть access-токен | -->
<!-- | `GET` | `/auth/me` | bearer-токен | Вернуть текущего пользователя (`id`, `email`, `is_admin`) | -->
<!---->
<!-- ### GraphQL (`/graphql`) -->
<!---->
<!-- Запросы (queries): -->
<!---->
<!-- | Query | Аутентификация | Описание | -->
<!-- | --- | --- | --- | -->
<!-- | `me` | аутентифицирован | Текущий пользователь | -->
<!-- | `users(search, limit, offset)` | администратор | Список пользователей с опциональной фильтрацией по email | -->
<!-- | `clients` | администратор | Список зарегистрированных OAuth-клиентов | -->
<!-- | `auditEvents(eventType, limit, offset)` | администратор | Список событий аудита | -->
<!---->
<!-- Мутации (mutations): -->
<!---->
<!-- | Mutation | Аутентификация | Описание | -->
<!-- | --- | --- | --- | -->
<!-- | `registerUser(email, password)` | нет | Создать пользователя; возвращает access-токен | -->
<!-- | `createClient(name, isConfidential)` | администратор | Создать OAuth-клиент | -->
<!-- | `disableUser(userId)` | администратор | Деактивировать пользователя | -->
## Пример GraphQL
Передайте JWT как bearer-токен:
```sh
curl http://localhost:8000/graphql/ \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer <token>' \
-d '{"query": "{ me { email } }"}'
```
Тело запроса:
```graphql
{ me { email } }
```
Пример ответа:
```json
{
"data": {
"me": {
"email": "user@example.com"
}
}
}
```
## Тестирование
```bash
uv run pytest -q
```
## Примечания
`.env` и `*.db` не коммитятся - они перечислены в `.gitignore` вместе с `__pycache__/`, `.venv/` и другими локальными артефактами
Держите секреты и локальные базы данных вне системы контроля версий