⟨/⟩ 50_Domain/Access/User.cs

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

using System;
using System.Collections.Generic;
using Ban.Sdaid.Notation.Documents;

namespace Ban.Sdaid.Icd.Domain.Access
{
    /// <summary>Пользователь Сервиса — учётная запись, через которую выполняется вход и определяются полномочия.</summary>
    [DomainEntity]
    public class User
    {
        /// <summary>Идентификатор пользователя.</summary>
        public Guid Id { get; init; }

        /// <summary>ФИО пользователя (для отображения).</summary>
        public string Name { get; init; }

        /// <summary>Логин (уникален).</summary>
        public string Login { get; init; }

        /// <summary>
        /// Пароль. На этапе разработки хранится открытым текстом (сид-данные);
        /// до продакшна заменяется на хеш + соль (см. ADR-SRV-006, «отложено»).
        /// </summary>
        public string Password { get; init; }

        /// <summary>Членство в группах полномочий — через него пользователь получает права.</summary>
        [Relation(Kind = RelationKind.Composition)]
        public IReadOnlyList<UserGroup> Groups { get; init; }

        /// <summary>Активные (выписанные и не отозванные) токены пользователя.</summary>
        [Relation(Kind = RelationKind.Composition)]
        public IReadOnlyList<UserActiveToken> ActiveTokens { get; init; }

        /// <summary>Отозванные токены пользователя (чёрный список).</summary>
        [Relation(Kind = RelationKind.Composition)]
        public IReadOnlyList<UserInvalidatedToken> InvalidatedTokens { get; init; }
    }

    /// <summary>Членство пользователя в группе полномочий (связь «пользователь — группа»).</summary>
    [DomainEntity]
    public class UserGroup
    {
        /// <summary>Идентификатор членства.</summary>
        public Guid Id { get; init; }

        /// <summary>Группа полномочий.</summary>
        [Relation]
        public Group Group { get; init; }
    }

    /// <summary>Описание доменной сущности <see cref="User"/>.</summary>
    public class UserSpec : IDomainEntityDocument
    {
        public Type Entity => typeof(User);

        public string Name => "Пользователь";

        public string Description =>
            @"Учётная запись Сервиса: через неё выполняется вход, и от её членства в группах зависят полномочия. Роли видения — хранитель и администратор — выражаются набором групп, а не отдельным полем.";

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

        public static string S1_Purpose = """
            ## Назначение

            Пользователь — субъект доступа. Он входит по логину и паролю, получает токен сессии и на
            каждый защищённый вызов предъявляет свои полномочия. Сами полномочия у пользователя не
            хранятся напрямую — они выводятся из групп, в которые он входит (группа → функции →
            claim-значения).

            Роли из видения (хранитель, администратор) — это **не отдельное поле**, а удобные наборы
            групп/функций: «хранитель» = функции ввода и проверки, «администратор» = функции
            конфигурации и управления доступом.
            """;

        public static string S2_Invariants = """
            ## Инварианты

            - Логин уникален.
            - Полномочия задаются только через членство в группах; прямых прав у пользователя нет.
            - Пароль на этапе разработки — открытым текстом (сид); до продакшна — хеш + соль.
            - Поля истории (`CreatedByUserId` / `AssignedToUserId` пакета) ссылаются на пользователя
              по идентификатору и заполняются из контекста вошедшего.
            """;

        public static string S99_Related = $"""
            ## Связанные артефакты

            - {nameof(Ban.Sdaid.Icd.Arch.Adr.ADR_011_AbacAuthorization)} — модель доступа (claims → функции → группы).
            - {nameof(Ban.Sdaid.Icd.Arch.Tech.CSharp.ADR_SRV_006_AuthImplementation)} — вход, токен, контекст, хранение пароля.
            - {nameof(Ban.Sdaid.Icd.Arch.Adr.ADR_004_CreatorVsAssignee)} — поля пользователя в истории пакета.
            """;
    }
}