feat: migrate to VitePress from monorepo docs, add test-contour section

This commit is contained in:
sova-bootstrap
2026-05-28 12:29:31 +03:00
parent e90dfe1bd4
commit e3e438df68
76 changed files with 11998 additions and 60 deletions
+85
View File
@@ -0,0 +1,85 @@
---
title: Логин по email и выдача JWT (Backend)
---
# Сценарий 1.1: Логин и JWT
## Бизнес-цель
Пользователь сайта или приложения входит по **email и паролю**. Система проверяет учётные данные, обновляет отметку последнего входа и выдаёт **JWT**, чтобы дальнейшие запросы к API выполнялись от имени этого пользователя без хранения сессии на сервере (stateless API).
## Точки входа
| Тип | Метод + URL | Класс |
| --- | --- | --- |
| HTTP | `POST /user/login` | `App\Controller\UserController::login` |
| HTTP | `GET /user/logout` | `App\Controller\UserController::logout` (ответ-заглушка; инвалидация токена на сервере не показана в коде) |
| HTTP | `GET /user/` | `App\Controller\UserController::index` — текущий пользователь по JWT (`#[IsGranted('ROLE_USER')]`) |
Асинхронные сообщения и CLI для этого сценария **не используются**.
## Пошаговый алгоритм (flow)
1. Клиент отправляет JSON с полями `username` (фактически email) и `password` (см. OpenAPI в контроллере).
2. `UserController::login` вручную парсит тело; при отсутствии полей отвечает `400` с текстом `Missing credentials`.
3. Значения кладутся в `App\Dto\UserLoginDto`; срабатывает Symfony Validator по атрибутам DTO.
4. Вызывается `App\Service\User\AuthenticationService::jsonAuth($dto)`:
- в `App\Repository\UserRepository` выполняется поиск `User` по **`email = md5(введённый email)`** (в БД в колонке `users.email` хранится **хэш**, а не открытый email);
- пароль проверяется через `UserPasswordHasherInterface::isPasswordValid`.
5. При неверной паре или отсутствии пользователя контроллер возвращает `400` с сообщением о неверных учётных данных.
6. При успехе вызывается `$user->updateLoggedIn()`, `EntityManager::flush()` — в БД обновляется поле `loggedIn`.
7. Lexik JWT: `JWTTokenManagerInterface::create($user)` формирует токен; в ответ уходит JSON: `successful`, `token`, `user` (массив из `User::toArray()``uid`, `bdate`, `roles`, `regionId`, `loggedIn`).
## Mermaid
```mermaid
sequenceDiagram
participant C as Клиент
participant UC as UserController
participant V as Validator
participant AS as AuthenticationService
participant UR as UserRepository
participant EM as EntityManager
participant JWT as JWTTokenManagerInterface
C->>UC: POST /user/login {username, password}
UC->>V: validate(UserLoginDto)
V-->>UC: ок / ошибки
UC->>AS: jsonAuth(dto)
AS->>UR: findOneBy email = md5(dto.email)
UR-->>AS: User | null
AS-->>UC: {user, isPasswordValid}
alt неверный пароль или нет пользователя
UC-->>C: 400
else успех
UC->>EM: flush (updateLoggedIn)
UC->>JWT: create(User)
UC-->>C: 200 {token, user}
end
```
## Внешние зависимости
| Система | Участие |
| --- | --- |
| PostgreSQL | таблица `users` (`App\Entity\User`) |
| Lexik JWT | генерация и последующая валидация токена |
| Bitrix / Инфоклиника / Redis / SMS | **не задействованы** в этом сценарии |
## Обработка ошибок и edge cases
- **Нет полей credentials** — `400`, `Missing credentials`.
- **Ошибки валидации DTO** — `400`, `successful: false`, `errors` (строка нарушений).
- **Неверный email/пароль** — единый ответ `400` с текстом «Не правильное имя пользователя или пароль».
- **Согласованность с JWT**: `App\Service\DecoderJWT\JWTDecoderService::getUser()` восстанавливает пользователя по `username` из payload и полю `email` в БД — это тот же «логин», что хранится в `User` после регистрационных сценариев (часто `md5(...)`).
## Ссылки на классы
- `apps/backend/src/Controller/UserController.php`
- `apps/backend/src/Service/User/AuthenticationService.php`
- `apps/backend/src/Dto/UserLoginDto.php`
- `apps/backend/src/Entity/User.php`
- `apps/backend/src/Repository/UserRepository.php`
- Конфигурация security/JWT: `apps/backend/config/packages/security.yaml`, `lexik_jwt_authentication.yaml`
См. также [backend-ddd.md](../backend-ddd.md).