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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions