⟨/⟩ 45_Api/Endpoints/Auth/LoginByPassword.cs

86 строк · в начало

using System;
using Ban.Sdaid.Notation.Documents;
using Ban.Sdaid.Icd;
using Ban.Sdaid.Icd.Api.Based;

namespace Ban.Sdaid.Icd.Api.Endpoints.Auth.LoginByPassword
{
    /// <summary>Документ-обёртка над endpoint входа по логину и паролю.</summary>
    public class DOC_LoginByPassword : IApiContractDocument, IFolder<ApiFolder>, IHasStructuralLinks
    {
        public SdaidLink[] Links => new[]
        {
            Rel.Uses<Ban.Sdaid.Icd.Backend.Handlers.Auth.LoginByPasswordHandler>(),
        };

        public static string _refName = "Endpoint LoginByPassword";

        public string Name => "Endpoint: LoginByPassword";

        public string Description =>
            @"Вход по логину и паролю: при успехе выписывается JWT для заголовка Authorization. Единственная ручка без токена. Поведение — LoginByPasswordHandler.";

        public string Version => "0.1";
        public string Status => "draft";
        public string[] Comments => new string[0];

        public static string Transport = """
            ## Транспорт

            `POST /api/Auth/LoginByPassword`, JSON-тело (`LoginByPasswordCommand` ниже). Помечен
            **`[AllowAnonymous]`** — единственный вход без токена (fallback-политика закрывает всё остальное).

            При успехе `Payload.Token` — JWT; фронт кладёт его в `localStorage` и шлёт в
            `Authorization: Bearer`. При неверных кредитах — `401` (ошибка в единой обёртке).
            """;

        public static string Body = $"""
            ## Endpoint

            {SdaidCode.OfClass<LoginByPasswordEndpoint>()}

            ## Command

            {SdaidCode.OfClass<LoginByPasswordCommand>()}

            ## Result

            {SdaidCode.OfClass<LoginByPasswordResult>()}

            ## Payload

            {SdaidCode.OfClass<LoggedInPayload>()}
            """;
    }

    /// <summary>Endpoint входа по паролю.</summary>
    public class LoginByPasswordEndpoint
    {
        public LoginByPasswordCommand? Input { get; set; }
        public LoginByPasswordResult? Output { get; set; }
    }

    /// <summary>Кредиты входа.</summary>
    public class LoginByPasswordCommand : BasedCommand
    {
        /// <summary>Логин.</summary>
        public string Login { get; init; } = "";

        /// <summary>Пароль (на этапе разработки сверяется как открытый текст).</summary>
        public string Password { get; init; } = "";
    }

    /// <summary>Результат входа: токен в поле Payload; при ошибке Payload = null.</summary>
    public class LoginByPasswordResult : BasedResult
    {
        public LoggedInPayload? Payload { get; init; }
    }

    /// <summary>Выданный токен сессии.</summary>
    public class LoggedInPayload
    {
        /// <summary>JWT access-token (несёт jti, IcdUserId, IcdUserLogin).</summary>
        public string Token { get; init; } = "";
    }
}