Включение идентификатора пользователя в события домена - PullRequest
0 голосов
/ 09 марта 2019

Я работаю над новым проектом управления документами, который использует архитектуру DDD.Я новичок в DDD и проектировании, управляемом событиями, так что это был опыт обучения.
Мое приложение структурировано так:

  • MyProgram.Domain
  • MyProgram.Infrastructure
  • MyProgram.App
  • MyProgram.WebApi

Домен обладает всей моей логикой домена, инфраструктура - это постоянство, приложение - это в основном команды и обработчики, а веб-интерфейс - это простовещь вебапи.

Сейчас я работаю над реализацией авторизации пользователей, и в настоящее время я решил использовать обработчики авторизации, которые будут выполнять проверку прав доступа перед выполнением команды или запроса.Я думаю, что это дает мне хорошую гибкость при выполнении сложной авторизации на основе ресурсов, поскольку многие из моих разрешений будут зависеть от текущего состояния определенного объекта.

Итак, до сих пор получалось, я реализовал авторизацию вмой прикладной уровень, оставляя большую часть пользовательских особенностей вне моей доменной модели.

Теперь проблема, которую я пытаюсь выяснить, состоит в том, как наилучшим образом включить информацию о пользователе в события моего домена, полученные из классов моего домена.

Например, у меня есть определенная совокупность, давайтескажем, его документ, и документ имеет определенный рабочий процесс утверждения.Поэтому, когда документ будет утвержден, я хочу вызвать событие домена, такое как

public class DocumentApproved : IDomainEvent
{
    public DocumentApproved (Package package)
    {
        DocumentId= document.Id;
        Timestamp = DateTime.Now;
    }
    public Guid Id { get; }
    public Guid UserId { get; }
    public DateTime Timestamp { get; }
    public Guid PackageId { get; }
}

Система должна быть поддающейся проверке, поэтому я планирую использовать события домена как в качестве контрольного журнала, так имеханизм, вызывающий побочные эффекты или сообщения других систем.

У сущности Document может быть метод, который выглядит примерно так:

 public void Approve()
    {
        State = State.Approve(this);
        ApprovalRevision.Next();
        Events.Add(new DocumentApproved(this));
    }

Мой вопрос

Я хотел бы включить UserIdпочти на каждом применимом событии домена, но я не могу придумать, как это сделать без необходимости, чтобы userId был параметром для каждого соответствующего метода в моих объектах домена, то есть они были бы только параметром ради созданиядоменные события, так как все действия типа авторизации будут происходить на прикладном уровне.

Это разумный способ приблизиться к этому, или, может быть, я должен пытаться захватить активность пользователя другим способом, таким как мой конвейер запросови оставить их отдельно от событий домена?Это звучит не совсем правильно для меня.Это действительно не такая проблема, чтобы userId был параметром для каждого метода, который может вызвать событие домена, но кажется, что это просто добавит беспорядок в каждую сигнатуру объекта домена.

Для поднятия событий моего домена я делаю нечто похожее на то, что предлагается здесь , где у сущности есть коллекция DomainEvents, и они публикуются через MediatR непосредственно перед сохранением сущности..

Ответы [ 2 ]

2 голосов
/ 09 марта 2019

Я думаю, что это дает мне хорошую гибкость при выполнении сложной авторизации на основе ресурсов, поскольку многие мои разрешения будут зависеть от текущего состояния определенного объекта.

Похоже, что авторизация является важной частью бизнес-правил и должна быть реализована на уровне домена. Тот факт, что вам необходимо обогатить события домена информацией о пользователе, является показателем того, что пользователь должен быть частью домена.

Не зная домена точно, я мог бы представить, что у вас есть инвариант, что-то вроде: «Документ может быть утвержден только линейным руководителем автора». Вы не можете утверждать этот инвариант в домене без понятия пользователей / ролей.

1 голос
/ 11 марта 2019

Наиболее прагматичный способ сделать это, вероятно, состоит в том, чтобы просто сохранить информацию о пользователе (вместе с другой информацией о сеансе / запросе) в качестве метаданных события (надеюсь, это поддерживает ваше хранилище событий) и обработать эту проблему за пределами домена.

Например, в одном приложении я написал реализацию хранилища событий, которую можно настроить с помощью EventMetadataProvider, который регистрируется в корне композиции приложения и использует текущий контекст запроса для добавления метаданных, таких как идентификатор пользователя, удаленный IP-адрес и т. д.

Обратите внимание, что вы все еще можете обогатить некоторые доменные события с помощью утверждающего / создателя / и т. Д. где это имеет наибольшее значение для потребителей событий, но в идеале не с общей концепцией UserId.

...