Skip to content

Изменение API AuthService #13

@oveeernight

Description

@oveeernight

Модернизация API AuthService.UserController

Тип: feature / api-change (breaking)
Приоритет: High
Статус: Proposal
Ответственная команда: AuthService

Контекст

Текущий контроллер UserController предоставляет:

  • POST /api/User — аутентификация по логину/паролю
  • GET /api/User — получение информации о текущем пользователе (по токену)

Проблемы:

  • Нестандартизованный ответ об ошибке (строка "Username of password incorrect" и 400 вместо 401/403), опечатка в тексте.
  • Отсутствие refresh-потока для продления access-токена.
  • Несогласованность кейсинга полей ответа (PascalCase вместо camelCase) с общим стилем фронтенда и OpenAPI-конвенциями.
  • Нет явной схемы ответов/ошибок в OpenAPI.
  • Маршрут GET лучше явно называть /me для ясности.

Предлагаемые изменения

  1. POST /api/User (Authenticate)
  • На вход: { login: string, password: string }
  • На успешный ответ 200:
    {
      "token": "<jwt>",
      "refreshToken": "<guid>",
      "userName": "<string>",
      "roles": ["<string>"] ,
      "avatar": "<url | null>",
      "userType": "<string>",
      "expiryTimeStamp": "<ISO8601>"
    }
  • На ошибки аутентификации: 401 с ProblemDetails (RFC 7807)
    {
      "type": "https://httpstatuses.com/401",
      "title": "Unauthorized",
      "status": 401,
      "detail": "Invalid login or password"
    }
  • На валидационные ошибки: 422 с ProblemDetails.
  • Поля ответа перевести в camelCase; добавить поле refreshToken.
  1. POST /api/User/refresh (Refresh Token) — НОВЫЙ
  • На вход:
    { "refreshToken": "<guid>" }
  • Ответ 200:
    {
      "token": "<jwt>",
      "refreshToken": "<guid>",
      "expiryTimeStamp": "<ISO8601>"
    }
  • Ошибки: 401 (просрочен/отозван/неизвестен refresh), 422 (невалидный формат), ProblemDetails.
  1. GET /api/User переименовать в GET /api/User/me (BREAKING)
  • Поведение прежнее: возвращает сведения о текущем пользователе согласно токену.
  • Ошибки: 401 при отсутствии/некорректном токене, ProblemDetails.
  1. Обновить OpenAPI-спецификацию
  • Описать схемы AuthRequest, AuthResponse, RefreshRequest, RefreshResponse, ProblemDetails.
  • Обновить securitySchemes (HTTP bearer JWT).
  • Задокументировать коды 200/401/422 для соответствующих эндпоинтов.

Миграция (для клиентов)

  • Заменить обращение к GET /api/User на GET /api/User/me.
  • Перейти на чтение полей ответа в camelCase (token, userName, ...), больше не полагаться на PascalCase.
  • Обрабатывать 401/422 как ошибки с телом формата ProblemDetails.
  • Для продления сессии использовать POST /api/User/refresh с сохранённым refreshToken.

Техническая реализация (кратко)

  • Контроллер:
    • Исправить тексты и коды ошибок: 401 вместо 400 при неверных учётных данных, ProblemDetails.
    • Возвращать camelCase через JsonSerializerOptions (PropertyNamingPolicy = CamelCase) или атрибуты, привести DTO к camelCase.
    • Добавить экшен POST api/User/refresh в UserController или отдельный TokenController (обсудить). Реализовать генерацию/хранение refresh-токенов (in-memory/репозиторий, TTL/ревокация).
    • GET переназвать на me и пометить старый маршрут как deprecated (временный период совместимости опционально).
  • Домен/сервис:
    • Расширить AuthService методами IssueTokens(login), Refresh(refreshToken).
    • Валидация и аудит использования refresh-токенов.
  • OpenAPI:
    • Обновить AuthService-openapi.json согласно новым схемам и маршрутам.

OpenAPI (черновик фрагментов)

  • Components
    • schemas:
      • AuthRequest { login: string, password: string }
      • AuthResponse { token: string, refreshToken: string, userName: string, roles: string[], avatar?: string, userType: string, expiryTimeStamp: string }
      • RefreshRequest { refreshToken: string }
      • RefreshResponse { token: string, refreshToken: string, expiryTimeStamp: string }
      • ProblemDetails { type?: string, title?: string, status?: number, detail?: string, instance?: string, errors?: object }
    • securitySchemes:
      • bearerAuth { type: http, scheme: bearer, bearerFormat: JWT }
  • Paths
    • POST /api/User
      • 200: AuthResponse
      • 401, 422: ProblemDetails
    • POST /api/User/refresh
      • 200: RefreshResponse
      • 401, 422: ProblemDetails
    • GET /api/User/me
      • security: bearerAuth
      • 200: User dto (как сейчас отдаёт AgentFromLogin), 401: ProblemDetails

Совместимость и риски

  • Breaking change в маршруте GET и формате кейсинга. Предложение: на один релиз оставить старый GET /api/User (deprecated) с предупреждением в ответе/логах.
  • Требуется хранение и безопасная ревокация refresh-токенов.

Критерии приёмки

  • Аутентификация с валидными учётными данными возвращает 200 и поля в camelCase, включая refreshToken.
  • Неверные учётные данные — 401 + ProblemDetails.
  • POST /api/User/refresh с валидным refreshToken возвращает новый набор токенов и обновлённый expiryTimeStamp.
  • GET /api/User/me возвращает корректные данные пользователя при валидном access-токене, 401 при невалидном.
  • OpenAPI отражает все маршруты/схемы и коды.

План задач

  • DTO: ввести AuthResponse, RefreshRequest, RefreshResponse, ProblemDetails-мэппинг
  • Контроллер: обновить POST /api/User, добавить POST /api/User/refresh, переименовать GET на /me
  • Домен: методы выдачи и обновления токенов, хранилище refresh-токенов
  • Обновить AuthService-openapi.json
  • Логи/метрики: аудит логинов и refresh-операций
  • Миграционная заметка для интеграторов

Дополнительно

  • Рассмотреть ограничение частоты попыток логина (rate limit) и капчу.
  • Рассмотреть сквозной correlationId в ответах ошибок (ProblemDetails.extensions).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions