--- 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).