Реализация DDD: пользователи и разрешения

16

Я работаю над небольшим приложением, пытаясь понять принципы доменного дизайна. В случае успеха это может быть пилот для более крупного проекта. Я пытаюсь следовать книге «Внедрение доменного дизайна» (Вон Вернон) и пытаюсь реализовать аналогичный простой дискуссионный форум. Я также проверил образцы IDDD на GitHub. У меня есть некоторые трудности с принятием Идентификации и Доступа к моему делу. Позвольте мне дать некоторую справочную информацию:

  • Я (надеюсь) понимаю причину разделения логики пользователей и разрешений: это вспомогательный домен, и это другой ограниченный контекст.
  • В основном домене нет пользователей, только Авторы, Модераторы и т. Д. Они создаются путем обращения к контексту Identity и Access с помощью службы, а затем трансляции полученных объектов User в и Moderator.
  • Доменные операции вызываются со связанной ролью в качестве параметра: например:

    ModeratePost( ..., moderator);

  • Метод объекта домена проверяет, является ли данный экземпляр Модератора ненулевым (экземпляр Модератора будет нулевым, если пользователь, запрашиваемый из контекста Identity and Access, не имеет роли Модератора).

  • В одном случае он выполняет дополнительную проверку перед изменением сообщения:

    if (forum.IsModeratedby(moderator))

Мои вопросы:

  • В последнем случае проблемы безопасности не смешиваются снова в основной области? Ранее в книгах говорилось, «кто может опубликовать тему или на каких условиях это разрешено. Форум просто должен знать, что автор делает это прямо сейчас».

  • Реализация на основе ролей в книге довольно проста: когда модератор является основным доменом, он пытается преобразовать текущий идентификатор пользователя в экземпляр модератора или в автора, когда это необходимо. Служба ответит соответствующим экземпляром или нулем, если у пользователя нет требуемой роли. Тем не менее, я не вижу, как я мог бы адаптировать это к более сложной модели безопасности; наш текущий проект, для которого я пилотирую, имеет довольно сложную модель с группами, ACL и т. д.

Даже с не слишком сложными правилами, такими как: «Сообщение должно редактировать только его владелец или редактор», этот подход, похоже, не работает, или, по крайней мере, я не вижу правильного способа его реализации.

Запрашивать контекст Identity and Access для экземпляра OwnerOrEditor не совсем правильно, и я получаю все больше и больше связанных с безопасностью классов в основном домене. Кроме того, мне нужно передать не только userId, но и идентификатор защищенного ресурса (id сообщения, форума и т. Д.) В контекст безопасности, который, вероятно, не должен заботиться об этих вещах (это правильно? )

Получив разрешения для основного домена и проверив их в методах объектов домена или в службах, я бы в итоге пришел к выводу: смешивать проблемы безопасности с доменом.

Я где-то читал (и я склонен с этим согласиться), что эти вещи, связанные с разрешениями, не должны быть частью основного домена, если только безопасность и разрешения не являются самим основным доменом. Оправдывает ли простое правило, подобное приведенному выше, обеспечение безопасности как части основного домена?

LittlePilgrim
источник
Может быть, вы можете найти то, что вам нужно здесь: stackoverflow.com/a/23485141/329660 Кроме того, тот факт , что контекст контроля доступа знает об идентификаторе ресурса , не означает, что он обладает знанием домена о том, что это за объект, или что он делает.
guillaume31
Спасибо, я видел этот пост ранее, моя проблема в том, что именно говорит в конце редактирование: я хотел бы вывести контроль доступа из основного домена, но я чувствую, что столкнулся со своей реализацией. Однако ваше предложение об идентификаторе ресурса имеет смысл: поскольку я использую не концепцию «Пользователь» или «Роль» в основной области, а конкретные роли, возможно, я мог бы использовать концепцию «Ресурс» в BC безопасности и сопоставить их с соответствующим конкретным объектом. Концепция домена. Стоит попробовать, спасибо!
LittlePilgrim
Разве примеры кода в ссылке, по крайней мере, не отвечают: «Я не вижу, как я мог бы адаптировать это к более сложной модели безопасности» ?
guillaume31
Моя проблема не в реализации самой модели безопасности, я не понимаю, как мне следует сопоставить эти более сложные правила с доменом. Как должно измениться отображение Пользователь -> Автор, если это не простая ролевая модель с точки зрения безопасности? Передача идентификаторов ресурсов в другой контекст может работать, HasPermissionToEdit(userId, resourceId)но я не считаю правильным загрязнять логику домена этими вызовами. Вероятно, я должен проверить это в методах службы приложения, прежде чем вызывать логику домена?
LittlePilgrim
Конечно, это должно быть в службах приложений ... Я думал, что это было ясно из частей кода, как UserService @AccessControlList[inf3rno]в ответе, с которым я связан.
guillaume31

Ответы:

6

Иногда трудно различить реальные правила контроля доступа и доменные инварианты, ограничивающие контроль доступа.

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

assert (forum.IsModeratedBy(moderator))Пример Вона Вернона, вероятно, должен был быть за пределами домена, но это не всегда возможно.

Мне нужно было бы передать не только userId, но и идентификатор защищенного ресурса (id сообщения, форума и т. Д.) В контекст безопасности, который, вероятно, не должен заботиться об этих вещах (это правильно?)

Если есть Security BC, и вы хотите, чтобы он обрабатывал эту логику, он не должен знать, что такое форум, но:

  • Он может просто знать такие понятия, как «модерируемый пользователем», и соответственно предоставлять или отказывать в правах доступа.
  • У вас может быть логика адаптера, которая подписывается на события Базового домена и преобразует их в простые пары (ключ ресурса, авторизованные пользователи) для хранения и использования Security BC.
guillaume31
источник
Поскольку оба ответа полезны и более или менее указывают в одном направлении, я проголосовал за них обоих. Я принял это, поскольку @ guillaume31 более или менее ответил на мой вопрос о реализации Вернона, и я продолжу свою реализацию, основываясь на его подсказке об использовании ресурсов в Security BC.
LittlePilgrim
Я должен сказать, что считаю это полностью противоположным моему ответу.
Эван
1
Возможно, я слишком запутался, но моя интерпретация была (для обоих ответов): 1. Хранить проблемы безопасности вне домена и использовать BC безопасности в качестве службы. 2. Вызвать службу перед вызовом любых объектов домена. 3. Служба. выполнит сопоставление пользователей / acls с модераторами, авторами и т. д. moderator = securityService.GetModerator(userId, forumId) 4. Доменная логика будет реализована в этих объектах, как в moderator.EditPost () 5. Методы, такие как EditPost, ничего не будут знать о концепциях безопасности, никаких дополнительных проверок не будет там
LittlePilgrim
Я все еще ищу ответы / указания по этому вопросу сам, но я обнаружил, что любая логика авторизации, которая зависит от текущего состояния объекта (например, если он в данный момент назначен модератору), на самом деле является бизнес-логикой, которая принадлежит Ваш домен и, кроме того, если он не находится в вашем домене, вы рискуете оказаться в недопустимом состоянии, если модель может быть обновлена ​​одновременно. Например, если вы подтверждаете право собственности с помощью политики, а затем переходите к обновлению этого объекта - во многих доменах это право собственности может измениться, и действие может перестать быть действительным.
Иордания
Если у вас нет очень сложного контекста совместной работы, вы, вероятно, можете позволить себе реализовать оптимистическую модель параллелизма с использованием управления версиями, но если ваши проверки не выполняются внутри или, по крайней мере, в отношении отдельного агрегатного экземпляра, то ваши проверки могут не соответствовать фактическим состояние объекта к тому времени, как вы сохраняете свои изменения.
Иордания
5

Аутентификация и авторизация - плохой пример для DDD.

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

Требование к бизнесу или домену: «Требуется проверка подлинности на основе ролей».

Затем вы проверяете роль перед вызовом доменной функции.

Там, где у вас есть сложные требования, такие как «я могу редактировать свои собственные сообщения, но не другие», убедитесь, что ваш домен разделяет функцию редактирования на EditOwnPost()и, EditOthersPost()таким образом, у вас есть простая функция для сопоставления ролей.

Вы также можете разделить функциональность на доменные объекты, например, Poster.EditPost()и Moderator.EditPost()это более подход ООП, хотя ваш выбор может зависеть от того, находится ли ваш метод в доменной службе или доменном объекте.

Однако вы выбираете разделять код, отображение ролей будет происходить за пределами домена. так, например, если у вас есть контроллер webapi:

PostController : ApiController
{
    [Authorize(Roles = "User")]
    public void EditOwnPost(string postId, string newContent)
    {
        this.postDomainService.EditOwnPost(postId, string newContent);
    }

    [Authorize(Roles = "Moderator")]
    public void EditOtherPost(string postId, string newContent)
    {
        this.postDomainService.EditOtherPost(postId, string newContent);
    }
}

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

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

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

Ewan
источник
4
Проверка роли "статически" немного упрощена. Что делать, если модератору не разрешено редактировать пост другого модератора? Разве эта проверка не должна быть частью домена?
Реда Хусни Алауи
2
@ RédaHousniAlaoui Мне тоже интересно об этом. Я не могу придумать способ справиться с этим, кроме как упоминания о пользователях / модераторах в домене или выполнения какой-то логики внутри этого ApiController, чтобы получить роль автора поста. Ничто из этого не кажется правильным, и, по моему опыту, это достаточно распространенная вещь, поэтому некоторые четкие указания были бы чрезвычайно полезны.
Джимми
1
@ Erwan, сценарий использования, о котором я говорю, динамический. Нечестно использовать предложение «Аутентификация и авторизация - плохой пример для DDD» на примере «Привет, мир!». DDD здесь, чтобы избежать случайной сложности и позволяет управлять сложностью домена. Динамические разрешения - это не случайная сложность и не то, чего не бывает в реальной жизни.
Реда Хусни Alaoui
1
ИМХО, проблема с вашим решением в том, что оно не удовлетворяет клиента. Клиент часто хочет иметь возможность динамически изменять эти отношения. Более того, это также происходит, когда поставщик предоставляет одно и то же корпоративное программное обеспечение разным компаниям. Если программное обеспечение плохо настроено, поставщик в конечном итоге умрет.
Реда Хусни Alaoui
1
«Но это, как правило, признается« плохой вещью », ваши настройки безопасности со временем становятся неуправляемыми, что фактически означает, что ваше приложение становится небезопасным». С правильным дизайном и тестированием, это полностью управляемо. Но из моего XP, чтобы произвести правильный дизайн, домен должен проверить разрешение. Альтернатива - утопия.
Реда Хусни Alaoui