Метод POST /api/v1/auth/login

Документация API: Аутентификация пользователя (Login) с генерацией JWT, содержащего Multi-Tenancy клеймы

Published

July 2, 2026

1 Функциональное назначение

Метод предназначен для аутентификации пользователя в системе по паре логин/пароль.

В рамках новой архитектуры этот метод выполняет роль транслятора контекста безопасности (Security Context Provider):

  1. Генерация токена сессии: Проверяет хэш пароля в СУБД и генерирует криптографически подписанный Access Token (JWT) [2026-07-02].
  2. Внедрение клеймов изоляции (JWT Claims): Намертво зашивает внутрь Payload токена параметры home_group_id, account_type и user_id. Это избавляет основные транзакционные микросервисы (Cook, Consume, Waste) от необходимости делать лишние JOIN-запросы в базу данных пользователей при каждом списании продуктов, так как шлюз FastAPI вычитывает контекст группы прямо из расшифрованного токена.

2 Протокол взаимодействия (HTTP Контракт)

  • Метод: POST
  • Маршрут: /api/v1/auth/login
  • Формат данных: application/json

2.1 Спецификация заголовков (HTTP Headers)

Заголовок Обязательный Описание Пример значения
Content-Type Да Формат передаваемых данных application/json
X-Request-ID Да Сквозной ID запроса для трассировки сессии авторизации req-auth-log-44bb

2.2 Спецификация тела запроса (Request Body)

Параметр Тип Обязательный Описание Пример значения
username String Да Уникальный логин пользователя (его email-адрес) user@somedomain.kz
password String Да Сырой текстовый пароль для сверки хэша MySecretPassword123

2.2.1 Пример сырого JSON-запроса (Payload):

{
  "username": "user@somedomain.kz",
  "password": "MySecretPassword123"
}

2.3 Спецификация успешного ответа (Response Body)

2.3.1 HTTP 200 OK

Возвращается при успешном совпадении учетных данных.

{
  "status": "success",
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c3ItODgyMiIsImhvbWVfZ3JvdXBfaWQiOiJncm91cC03NzItYWxwaGEiLCJhY2NvdW50X3R5cCI6IkhPTUUiLCJleHAiOjE3ODMzMDk2MDB9.signature...",
  "expires_in": 3600
}

3 Схема обработки запроса пользователя (Mermaid)

На диаграмме представлена логика аутентификации. Сервис Authorization сверяет хэш пароля в PostgreSQL, извлекает параметры привязки к пространству и генерирует JWT-токен, содержащий зашитые JWT Claims.

sequenceDiagram
    autonumber
    
    actor App as APP (Мобильное приложение)
    participant Nginx as Nginx Proxy
    participant GW as GATEWAY (backend-api)
    participant Auth as AUTH (auth-service)
    participant DB as DB_AUTH (PostgreSQL)

    App->>Nginx: Шаг 1: POST /api/v1/auth/login (email, password)
    activate Nginx
    Nginx->>GW: Шаг 2: POST /backend-api/v1/auth/login
    activate GW
    GW->>Auth: Шаг 3: gRPC: LoginUser(LoginRequest)
    activate Auth
    
    Auth->>DB: Шаг 4: SQL SELECT id, password_hash FROM users...
    activate DB
    DB-->>Auth: Шаг 5: Возврат хэша пароля
    deactivate DB
    
    note over Auth: Шаг 5 (продолжение):<br/>Крипто-валидация пароля
    note over Auth: Шаг 6: Внутренний метод<br/>GenerateTokenPair(user_id)
    
    Auth->>DB: Шаг 7: SQL INSERT INTO user_sessions...
    activate DB
    DB-->>Auth: Подтверждение записи сессии
    deactivate DB
    
    Auth-->>GW: Шаг 8: gRPC: LoginResponse
    deactivate Auth
    GW-->>App: Шаг 9: HTTP 200 OK (access, refresh)
    deactivate GW
    deactivate Nginx
    
    note over App: Шаг 10: Внутренний метод<br/>SecureStorage.write(...)

Процесс авторизации пользователя (Login)

4 Расшифровка шагов и Анатомия JWT Payload

Шаг Действие Параметры Ошибки (Исключения / Статусы)
Шаг 1 (APP -> NGINX) Мобильное приложение отправляет сырые учетные данные пользователя на внешний порт шлюза. HTTP POST /api/v1/auth/login
Body: {"email": "...", "password": "..."}
DioException: connection timeout
Шаг 2 (NGINX -> GATEWAY) Nginx перенаправляет чистый трафик на API Gateway (backend-api). HTTP POST /backend-api/v1/auth/login HTTP 502 Bad Gateway
Шаг 3 (GATEWAY -> AUTH) API Gateway проверяет структуру Pydantic-модели и вызывает внутренний gRPC-метод аутентификации. gRPC: LoginUser(LoginRequest) HTTP 422 Unprocessable Entity
Шаг 4 (AUTH -> DB_AUTH) Микросервис auth-service запрашивает из СУБД хэш пароля по указанному Email. SQL SELECT id, password_hash FROM users WHERE email = $1 gRPC: NOT_FOUND \(\rightarrow\) HTTP 401 Unauthorized
Шаг 5 (DB_AUTH -> AUTH) База данных возвращает хэш. Сервис проводит валидацию пароля внутренним крипто-методом. Проверка хэша пароля gRPC: UNAUTHENTICATED \(\rightarrow\) HTTP 401 Unauthorized
Шаг 6 (AUTH -> AUTH) Внутреннее действие: При успешном совпадении пароля генерируется новая пара Access/Refresh токенов. Вызов: GenerateTokenPair(user_id) JWT: SignatureGenerationError
Шаг 7 (AUTH -> DB_AUTH) Сервис сохраняет метаданные созданной сессии в PostgreSQL. SQL INSERT INTO user_sessions ... PostgreSQL: database is read-only
Шаг 8 (AUTH -> GATEWAY) gRPC-ответ с токенами передается обратно на API Gateway. gRPC: LoginResponse gRPC: CANCELLED
Шаг 9 (GATEWAY -> APP) Шлюз формирует финальный JSON и транслирует его мобильному приложению. HTTP 200 OK
Body: {"access_token": "...", "refresh_token": "..."}
HTTP 500 Internal Server Error
Шаг 10 (APP -> APP) Мобильное приложение перехватывает ответ и фиксирует сессию локально в безопасном хранилище. Вызов: SecureStorage.write(...) SecureStorageException

4.1 Анатомическая структура декодированного JWT Payload (Claims):

Когда транзакционный бэкенд-шлюз или сторонний ИИ-микросервис расшифровывают токен, они без обращения к БД видят следующий стандартизированный JSON-датасет:

{
  "sub": "usr-8822-fa41",
  "home_group_id": "group-772-alpha",
  "account_type": "HOME",
  "iss": "auth-service",
  "iat": 1783306000,
  "exp": 1783309600
}
  • sub (Subject) — уникальный user_id автора операции для логирования действий.
  • home_group_id — UUID/строковый идентификатор целевого холодильника семьи или офиса. По нему фильтруются все SQL-запросы WHERE home_group_id = $1.
  • account_type — флаг контура (HOME или OFFICE), управляющий вилками ухода в виртуальный минус или жесткой блокировки дефицита.
  • exp (Expiration Time) — время жизни токена (3600 секунд / 1 час), по истечении которого Flutter-клиент обязан запустить фоновое обновление сессии.

5 Спецификация вилок исключений и обработки ошибок

При аутентификации система обрабатывает ошибки безопасности на Шаге 5, не раскрывая наружу, какая именно часть учетных данных была неверной. Это защищает контур от перебора логинов злоумышленниками.

5.1 1. Ошибка: Неверный логин или пароль (HTTP 401 Unauthorized)

Вызывается на Шаге 5, если хэш пароля не совпал, либо если указанный email полностью отсутствует в базе данных пользователей PostgreSQL.

  • Заголовки ответа (Response Headers):
    • Content-Type: application/json
  • Тело ответа (Response Body):
{
  "error_code": "ERR-INVALID-CREDENTIALS",
  "message": "Неверный логин или пароль. Доступ к системе отклонен.",
  "details": {
    "action": "Prompt user to re-enter credentials or trigger password recovery flow."
  }
}

5.2 2. Ошибка валидации формата email (HTTP 422 Unprocessable Entity)

Возвращается на Шаге 4 бэкенд-шлюзом FastAPI, если переданная строка в поле username не соответствует валидному синтаксису адреса электронной почты.

{
  "error_code": "ERR-VALIDATION-FAILED",
  "message": "Передан некорректный формат логина (требуется валидный email).",
  "details": [
    {
      "loc": ["body", "username"],
      "msg": "value is not a valid email address",
      "type": "value_error.email"
    }
  ]
}