Лабараторная 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 токены
Установка
git clone https://vantablacktea.ddns.net/Agzamus/scripts-2.git
cd scripts-2
С помощью uv
uv sync
uv run python run.py
Тесты:
uv run pytest -q
Альтернатива с pip
Linux:
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
Windows:
python -m venv .venv
source .venv\Scripts\activate
pip install -r requirements.txt
Настройка
Необходимо создать .env файл, например скопировав пример:
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 |
Заголовок приложения |
Запуск
Примените миграции базы данных, затем запустите сервер:
uv run alembic upgrade head # создать/обновить схему базы данных
uv run python run.py # uvicorn на 0.0.0.0:8000 с reload
Или напрямую:
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"]
Заполнение:
Убедитесь, что схема создана (запустите один раз или при каждом изменении миграций):
uv run alembic upgrade head
Запустите скрипт заполнения:
uv run python seed.py
Запустите сервер:
uv run python run.py
Админ панель: http://localhost:8000/admin
Свои учётные данные
Переопределите значения по умолчанию через переменные окружения, например:
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-скрипта обходят политику стойкости при регистрации
Сброс
Чтобы сбросить базу данных:
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-токен:
curl http://localhost:8000/graphql/ \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer <token>' \
-d '{"query": "{ me { email } }"}'
Тело запроса:
{ me { email } }
Пример ответа:
{
"data": {
"me": {
"email": "user@example.com"
}
}
}
Тестирование
uv run pytest -q
Примечания
.env и *.db не коммитятся - они перечислены в .gitignore вместе с __pycache__/, .venv/ и другими локальными артефактами
Держите секреты и локальные базы данных вне системы контроля версий