Перейти к основному содержимому

POST /api/investors/me/2fa/enable-request — Запрос включения 2FA (requestEnableTwoFactor)

Назначение

Первый шаг включения двухфакторной аутентификации: отправить СМС-код на текущий подтверждённый телефон пользователя и создать запрос подтверждения с целью EnableTwoFactor. Вызывается аутентифицированным пользователем. Включение применит confirm-enable-two-factor.md (INV-7: 2FA меняется только после подтверждения кодом).

Metadata

ПолеЗначение
Сервис/контекстidentity
API areapublic
Feature groupsecurity
Статусapproved
Документdocs/06-services/identity/api/investor/request-enable-two-factor.md

Актор и доступ

ПроверкаЗначение
Actor typeUser (Bearer JWT)
Auth policy / Permissionsauthenticated; permission identity.security.manage-self
Scope (RBAC)self
Record-levelтолько собственная запись; код уходит только на телефон владельца
Tenant isolationне применяется (ADR-0052)
Auditsecurity-sensitive: факт запроса логируется

HTTP-контракт

ПолеЗначение
MethodPOST
Route/api/investors/me/2fa/enable-request
Success status200
Idempotency headerне применяется (повтор гасит предыдущий Pending — INV-S1 Superseded)
Correlationсквозной trace через traceparent

Входные данные / параметры запроса

Body отсутствует.

ПолеИсточникТипОбязательностьВалидация / ОграниченияБезопасность
UserIdidentity claims (sub)GuidДавалидный JWT401 без токена
IpAddress / UserAgentmiddlewarestring?Нет≤ 45 / ≤ 512rate-limit / анти-фрод

Модель ответа RequestEnableTwoFactorCommandResult

ПолеТипОбязательностьИсточникMaskingОписание
twoFactorConfirmationRequestIdstring (Guid)ДаSignInConfirmationRequest.IdИдентификатор запроса (confirm ищет Pending по пользователю + цели; id — для трассировки/UI).
realConfirmationCodeDispatchedboolДаverifierfalse — код не отправлялся реально (тестовый контур).

Алгоритм

  1. Контекст и доступ. Операцию выполняет аутентифицированный пользователь над собственной записью (UserId из токена); из middleware известны IpAddress/UserAgent.
  2. Проверка и лимиты. Rate-limit (INV-S4, по телефону пользователя + IP) — превышение ⇒ IDENTITY_CONFIRMATION_RATE_LIMITED (429).
  3. Проверки состояния. Получить пользователя; он Active — иначе IDENTITY_USER_BLOCKED; 2FA ещё не включена — иначе IDENTITY_TWO_FACTOR_ALREADY_ENABLED (идемпотентность цели).
  4. Правила и маппинг. Сгенерировать код (CSPRNG, 4–6 цифр); создать запрос подтверждения (INV-S8): цель EnableTwoFactor, UserId, PhoneNumber = текущий телефон пользователя (не из входа), хэш кода (HMAC-SHA256), ExpiresAt = now + 5 мин, IpAddress, UserAgent; фиксируется доменное событие ConfirmationCodeRequestedEvent (→ СМС-verifier).
  5. Что меняется. В одном согласованном изменении: прежний активный (Pending) запрос той же цели гасится в Superseded (INV-S1) и создаётся новый запрос.
  6. События. Интеграционных нет; доменное ConfirmationCodeRequestedEvent → СМС-verifier.
  7. Результат. twoFactorConfirmationRequestId, realConfirmationCodeDispatched; HTTP 200.

Диаграмма

Побочные эффекты

ТипДетали
Интеграционные событияnone
Внешние вызовыСМС-verifier (timeout 5 с, 1 retry)
Проекции / поискrate-limit-счётчик
УведомленияСМС с кодом на текущий номер

Предусловия и постусловия

  • Пред: пользователь аутентифицирован и Active; 2FA ещё выключена (IsTwoFactorEnabled = false); есть текущий подтверждённый телефон (код уходит на него, не из входа).
  • Пост (успех): создан Pending-запрос цели EnableTwoFactor (TTL 5 мин); прежний Pending той же цели погашен в Superseded (INV-S1); СМС-код отправлен. IsTwoFactorEnabled не меняется — включение применит только confirm-enable-two-factor.md по коду (INV-7).

Ошибки и failure modes

КодHTTP statusУсловиеСообщениеRetry
— (auth)401Нет/просрочен JWTклиент выполняет re-loginre-login
IDENTITY_TWO_FACTOR_ALREADY_ENABLED4002FA уже включена«2FA уже включена»no retry
IDENTITY_USER_BLOCKED400Status != Active«Учётная запись заблокирована»no retry
IDENTITY_CONFIRMATION_RATE_LIMITED429INV-S4«Слишком много запросов кода»retry ≥ 60 сек
IDENTITY_SMS_DISPATCH_FAILED400Отказ verifier«Не удалось отправить код»retry

Acceptance Criteria

  • Given Active-пользователь с выключенной 2FA, When POST .../2fa/enable-request, Then создан Pending-запрос EnableTwoFactor, код отправлен на текущий телефон владельца, ответ 200 с twoFactorConfirmationRequestId и realConfirmationCodeDispatched; IsTwoFactorEnabled не тронут.
  • Given уже есть активный Pending-запрос EnableTwoFactor, When повторный запрос, Then прежний → Superseded (INV-S1), создаётся новый, отправляется новый код.
  • Given 2FA уже включена, When запрос, Then IDENTITY_TWO_FACTOR_ALREADY_ENABLED (400, идемпотентность цели).
  • Given учётка Blocked/Archived, When запрос, Then IDENTITY_USER_BLOCKED (400).
  • Given превышен лимит отправки кода (INV-S4, по телефону + IP), When запрос, Then IDENTITY_CONFIRMATION_RATE_LIMITED (429), retry ≥ 60 сек.
  • Given verifier отказал после retry, When запрос, Then IDENTITY_SMS_DISPATCH_FAILED (400).
  • Given запрос без валидного JWT, When запрос, Then 401, клиент уходит на re-login.

Совместимость и наблюдаемость

  • Новые optional поля — additive.
  • Logs: UserId, маскированный номер; metrics: identity_2fa_enable_requests_total; traces — OTel.

Обратные ссылки

Автоссылки: где используется этот документ.

Связанные документы