Files
scripts-2/README.md
T

270 lines
9.4 KiB
Markdown
Raw Normal View History

2026-10-12 19:48:57 +03:00
# Лабараторная 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/` и другими локальными артефактами
Держите секреты и локальные базы данных вне системы контроля версий