using System;
using Ban.Sdaid.Notation.Documents;
using Ban.Sdaid.Icd;
using Ban.Sdaid.Icd.Api.Endpoints.Auth.LoginByPassword;
using Ban.Sdaid.Icd.Domain.Access;
namespace Ban.Sdaid.Icd.Backend.Handlers.Auth
{
/// <summary>Handler входа по логину и паролю.</summary>
public class LoginByPasswordHandler : IHandlerDocument, IFolder<BackendFolder>, IHasStructuralLinks
{
public SdaidLink[] Links => new[]
{
Rel.Uses<Ban.Sdaid.Icd.Domain.BC_Icd>(),
Rel.Uses<UserSpec>(),
Rel.Uses<UserTokenSpec>(),
Rel.Uses<DOC_LoginByPassword>(),
};
public static string _refName = "Handler LoginByPassword";
public string Name => "Handler: LoginByPassword";
public string Description =>
@"Что произойдёт при вызове endpoint LoginByPassword: сверить кредиты, выписать JWT с уникальным jti и учесть активный токен.";
public string Version => "0.1";
public string Status => "draft";
public string[] Comments => new string[0];
public static string Purpose = $"""
## Назначение
Канонический сценарий обработки {SdaidAnchors.RefTo<DOC_LoginByPassword>()}
(`{nameof(LoginByPasswordCommand)}`). Единственная ручка **без проверки права** — помечена
`[AllowAnonymous]`, иначе войти было бы нечем.
""";
public static string Scenario = $"""
## Сценарий вызова
1. Найти пользователя ({SdaidAnchors.RefTo<UserSpec>()}) по `{nameof(LoginByPasswordCommand.Login)}`.
Не найден — `401` (не раскрывая, логин или пароль неверны).
2. Сверить `{nameof(LoginByPasswordCommand.Password)}`. На этапе разработки — как открытый текст
(хеш отложен, см. ADR-SRV-006). Не совпал — `401`.
3. Сгенерировать `jti` (UUID v7) и JWT (несёт `jti`, `IcdUserId`, `IcdUserLogin`); срок жизни — из
конфигурации.
4. Записать активный токен ({SdaidAnchors.RefTo<UserTokenSpec>()}: `Jti`, `IssuedAt`, `ExpiresAt`);
заодно подчистить истёкшие активные записи.
5. Вернуть `{nameof(LoginByPasswordResult)}` с токеном в `{nameof(LoggedInPayload)}`.
Права здесь не проверяются (вход). Формирование контекста и claims — при последующих запросах.
""";
}
}