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