--- title: Авторизация по UID и pcode (Backend) --- # Сценарий 1.2: Авторизация по **UID** и **pcode** ## Бизнес-цель Часть пользователей приходит из медицинской системы (**Инфоклиника / MIS**): у пациента уже есть **числовой идентификатор** в сторонней системе. Сайт должен позволить: - связать этот **UID** с учётной записью в API (`App\Entity\User::uid`); - войти **по email+паролю**, если пользователь уже создан с тем же `uid`; - войти **по pcode + дате рождения**, если личный кабинет строится на «медицинском» коде без ввода email на первом шаге. ## Что такое `uid` и `pcode` в коде | Термин в API | Где в коде | Смысл | | --- | --- | --- | | `uid` | поле `User::$uid`, уникальное `int` | Идентификатор пациента/пользователя из внешней системы (в т.ч. MIS). | | `pcode` в `POST /user/auth-by-pcode` | мапится в `UserUidAuthDto::$uid` | Тот же **числовой идентификатор**, что и `uid`; название «pcode» — контракт фронта/legacy. | Откуда берутся значения **на практике**: из МИС/личного кабинета после идентификации пациента (конкретный HTTP-запрос к Инфоклинике **в этом приложении** для «получить pcode» в сценарии логина не вызывается — клиент передаёт уже известные `uid`/`pcode` и дату рождения). ## Точки входа | Тип | Метод + URL | Класс | | --- | --- | --- | | HTTP | `POST /user/auth` | `UserController::auth` | | HTTP | `POST /user/auth-by-pcode` | `UserController::authByPcode` | ## Пошаговый алгоритм — `POST /user/auth` 1. Тело: `uid`, `regionId`, `email`, `password`, опционально `bdate` → `UserAuthDto`, валидация. 2. `AuthenticationService::jwtAuth(dto)`: - `UserRepository::findOneBy(['uid' => $dto->uid])`; - если пользователь есть — проверка пароля **введённого** `password` через `passwordHasher`; - если пользователя **нет** — возвращается `user: null` (флаг пароля не применяется). 3. Если пароль не совпал при существующем пользователе — `400`, как при обычном логине. 4. Если пользователя не было — `RegistrationService::create(dto)`: - `setEmail(md5($dto->email))` (в БД снова **не** хранится открытый email); - `setUid`, `setRegionId`, роли `ROLE_USER`, `birthDate` из `bdate` (формат `Ymd`), хэш пароля. 5. `updateLoggedIn`, `flush`, выдача JWT через `JWTTokenManagerInterface::create`. ## Пошаговый алгоритм — `POST /user/auth-by-pcode` 1. Тело: `pcode` (кладётся в `UserUidAuthDto::$uid`), `birthDate` или `bdate`. 2. Валидация DTO, разбор даты (`Ymd` или `Y-m-d`). 3. `UserRepository::findOneByUidAndBirthDate($uid, $birthDate)` — сравнение даты **по диапазону суток**. 4. Если не найден — `RegistrationService::createByUidAndBirthDate`: - `email = md5((string) uid)` — синтетический идентификатор для колонки `email` / JWT `username`; - регион по умолчанию `1` (аргумент сервиса); - пароль по умолчанию: `hash( md5(uid . birthDateRaw) )` где первая часть — конкатенация строк из DTO перед нормализацией даты в сущности. 5. `updateLoggedIn`, `flush`, JWT в ответе. ## Mermaid ```mermaid flowchart TD A[POST /user/auth или /user/auth-by-pcode] --> V{Валидация DTO} V -->|ошибка| E400[400 errors] V -->|ок| B{Какой маршрут?} B -->|auth| C[jwtAuth по uid] C --> D{User найден?} D -->|да| P[проверка password] P -->|fail| E400b[400 неверный пароль] P -->|ok| T[JWT + loggedIn] D -->|нет| R[RegistrationService.create] R --> T B -->|auth-by-pcode| F[findOneByUidAndBirthDate] F -->|есть| T F -->|нет| G[createByUidAndBirthDate] G -->|исключение| E500[500] G -->|ok| T ``` ## Внешние зависимости | Система | Участие | | --- | --- | | PostgreSQL | `users` | | Инфоклиника | **не вызывается напрямую** в этих методах; идентификатор приходит от клиента | | JWT (Lexik) | выдача токена | ## Обработка ошибок и edge cases - **Неверный формат даты** в `auth-by-pcode` — `400` с подсказкой по форматам. - **Ошибка при создании пользователя** — `500` с текстом исключения (может раскрывать внутренние детали — вопрос hardening). - **Коллизии `uid`**: на уровне сущности `User` есть ограничение уникальности `uid`; при конфликте БД вернёт ошибку при `flush` (в этом контроллере не разобрана отдельно). ## Ссылки на классы - `apps/backend/src/Controller/UserController.php` (`auth`, `authByPcode`) - `apps/backend/src/Service/User/AuthenticationService.php` (`jwtAuth`) - `apps/backend/src/Service/User/RegistrationService.php` (`create`, `createByUidAndBirthDate`) - `apps/backend/src/Dto/UserAuthDto.php`, `UserUidAuthDto.php` - `apps/backend/src/Repository/UserRepository.php` (`findOneByUidAndBirthDate`) См. [backend-ddd.md](../backend-ddd.md) (контекст Identity).