Впровадження DDD: користувачі та дозволи


16

Я працюю над невеликим додатком, намагаючись зрозуміти принципи доменного дизайну. У разі успіху це може бути пілотним проектом для більшого проекту. Я намагаюся слідкувати за книгою "Впровадження дизайну, керованої доменом" (автор Вон Вернон) і намагаюся реалізувати подібний, простий дискусійний форум. Я також перевірив зразки IDDD на github. У мене є певні труднощі з прийняттям ідентичності та доступу до моєї справи. Дозвольте надати довідкову інформацію:

  • Я (сподіваюсь) розумію міркування щодо розділення логіки користувачів та дозволів: це допоміжний домен, і це інший обмежений контекст.
  • У основному домені немає користувачів, лише Автори, Модератори тощо. Вони створюються, звертаючись до контексту Identity та Access за допомогою сервісу, а потім переводячи отримані об’єкти Користувача до Модератора.
  • Операції з доменом викликаються пов'язаною роллю в якості параметра: наприклад:

    ModeratePost( ..., moderator);

  • Метод об’єкта домену перевіряє, чи вказаний примірник Модератора не є нульовим (екземпляр Модератора буде нульовим, якщо користувач запитав з контексту Identity and Access не має ролі Модератора).

  • В одному випадку він робить додаткову перевірку перед зміною публікації:

    if (forum.IsModeratedby(moderator))

Мої запитання:

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

  • Реалізація на основі ролей у книзі є досить простою: коли модератор є основним доменом, він намагається перетворити поточний користувальницький ідентифікатор в екземпляр Модератора або в автора, коли це потребує. Сервіс відповість відповідним екземпляром або нулем, якщо користувач не має необхідної ролі. Однак я не бачу, як я міг би адаптувати це до більш складної моделі безпеки; наш нинішній проект, над яким я пілотую, має досить складну модель з групами, ACL тощо.

Навіть із правилами, які не дуже складні, як-от: "Публікацію слід редагувати лише її власником чи редактором", такий підхід здається порушеним, або, принаймні, я не бачу правильного способу його виконання.

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

Перетягнувши дозволи на основний домен і перевіривши їх у методах об’єктів домену або в службах, я б закінчився на квадратному: змішування проблем безпеки з доменом.

Я десь читав (і я з цим погоджуюся), що ці речі, пов'язані з дозволом, не повинні бути частиною основного домену, якщо тільки безпека та дозволи не є основним доменом. Чи виправдовує таке просте правило, як наведене вище, що робить безпеку частиною основного домену?


Можливо, ви можете знайти тут те, що вам потрібно: stackoverflow.com/a/23485141/329660 Крім того, лише те, що контекст контролю доступу знає про ідентифікатор ресурсу , не означає, що він має доменні знання про те, що це сутність, що є ресурсом або що це робить.
guillaume31

Дякую, я вже бачив цю публікацію раніше, моя проблема полягає саме в тому, що в редакції говориться наприкінці: я хотів би перенести контроль доступу зі свого основного домену, але я відчуваю, що зі своїм реалізацією я потрапив у стіну. Однак ваша пропозиція щодо ідентифікатора ресурсу має сенс: оскільки я не використовую поняття User або Role в основній області, а конкретні ролі, можливо, я міг би використати поняття Resource в безпеці BC і віднести їх до відповідного конкретного концепція домену. Варто спробувати, дякую!
LittlePilgrim

Чи не зразки коду у посиланні принаймні відповідають на "Я не бачу, як я можу адаптувати це до більш складної моделі захисту" ?
guillaume31

Моя проблема полягає не в реалізації самої моделі захисту, я не можу зрозуміти, як я повинен відображати ці більш складні правила в домен. Як слід змінювати відображення користувача -> автора, якщо це не проста модель на основі ролі з боку безпеки? Передача ідентифікаторів ресурсів в інший контекст може спрацювати, як-от, HasPermissionToEdit(userId, resourceId)але я не вважаю правильним забруднювати логіку домену цими дзвінками. Ймовірно, я повинен перевірити їх у методах обслуговування додатків, перш ніж звертатися до логіки домену?
LittlePilgrim

Звичайно, це повинно бути в службах додатків ... Я думав, що це зрозуміло з частин коду, як UserService @AccessControlList[inf3rno]у відповіді, до якої я пов’язаний.
guillaume31

Відповіді:


6

Іноді важко відрізнити між реальними правилами контролю доступу та інваріантами доменів, які обмежують обмеження на контролі доступу.

Тим більше, правила, які залежать від даних, доступних лише далеко в ході певної логіки домену, не можуть бути легко витягнутими з домену. Зазвичай контроль доступу викликається до або після операції над доменом, але не під час.

assert (forum.IsModeratedBy(moderator))Приклад Вуна Вернона, ймовірно, мав бути поза Доменом, але це не завжди можливо.

Мені потрібно передати не лише userId, а ідентифікатор захищеного ресурсу (ідентифікатор повідомлення, форуму тощо) до контексту безпеки, який, ймовірно, не повинен перейматися цими речами (чи правильно це?)

Якщо є БЦ безпеки і ви хочете, щоб він обробляв цю логіку, він не повинен детально знати, що таке Форум, але:

  • Він може просто знати такі поняття, як "модерується", і надавати або забороняти права доступу відповідно.
  • Ви можете мати логіку адаптера, яка підписує події Core Domain і переводить їх у прості пари значень ключів (ресурс, дозволені користувачі) для БЦ безпеки для зберігання та використання.

Оскільки обидві відповіді корисні і більш-менш вказують на той самий напрямок, я обирав їх обох. Я прийняв це, оскільки @ guillaume31 більш-менш відповів на моє запитання про реалізацію Вернона, і я продовжуватиму свою реалізацію, грунтуючись на його підказці щодо використання ресурсів у БК.
LittlePilgrim

Треба сказати, що я вважаю це цілком протилежною моїй відповіді.
Еван

1
Можливо, я зараз занадто розгублений, але моє тлумачення було (для обох відповідей): 1. Не допускайте проблем із безпеки домену та використовуйте БЦ захист як послугу 2. Зателефонуйте в службу, перш ніж викликати будь-які об’єкти домену 3. Служба зробить відображення від користувачів / acls до модераторів, авторів тощо. moderator = securityService.GetModerator(userId, forumId) 4. Логіка домену буде реалізована в таких об'єктах, як у модераторі. там
LittlePilgrim

Я все ще шукаю відповіді / вказівки на це, але я виявив, що будь-яка логіка авторизації, яка спирається на поточний стан об'єкта (наприклад, якщо він наразі призначений модератору), є насправді діловою логікою, до якої належить ваш домен. Крім того, якщо він не знаходиться у вашому домені, ви ризикуєте стати недійсним, якщо модель може бути оновлена ​​одночасно. Наприклад, якщо ви підтвердили право власності за допомогою політики, а потім перейдіть до оновлення цього об’єкта - у багатьох областях ця власність може бути змінена, і дія більше не може бути дійсною.
Йорданія

Якщо у вас дуже складний контекст спільної роботи, ви, мабуть, можете дозволити собі впровадити тут оптимістичну модель одночасності з використанням версій, але якщо ваші перевірки не здійснюються в межах або принаймні щодо конкретного сукупного екземпляра, то ваші чеки можуть не відповідати фактичним стан об'єкта до моменту, коли ви зберігаєте свої зміни.
Йорданія

5

Автентифікація та авторизація є поганим прикладом для DDD.

Жодне з цих речей не є частиною домену, якщо ваша компанія не створює продукти безпеки.

Вимога компанії або домену є або повинна бути "мені потрібна автентифікація на основі ролі"

Потім ви перевіряєте роль перед викликом функції домену.

Якщо у вас є складні вимоги, такі як "Я можу редагувати власні публікації, але не інші", переконайтеся, що ваш домен відокремлює функцію редагування, EditOwnPost()і EditOthersPost()щоб у вас була проста функція відображення ролей

Ви також можете розділити свою функціональність на об’єкти домену, такі як, Poster.EditPost()і Moderator.EditPost()це більш підхід OOP, хоча ваш вибір може залежати від того, чи буде ваш метод у службі домену або об’єкт домену.

Однак ви вирішите відокремити код, Рольове відображення відбуватиметься поза Доменом. так, наприклад, якщо у вас є контролер 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);
    }
}

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

Домен визнає різницю дій, але вимога безпеки полягає лише в тому, що "функціональність може бути обмежена ролями" .

Це, можливо, зрозуміліше з розділенням об'єктів домену, але по суті ви перевіряєте метод, який будує об'єкт, а не метод, який викликає сервісний метод. Ваша вимога, якщо ви все ще хочете озвучити це як частину домену, стане "лише модератори можуть сконструювати об'єкт модератора"


4
Перевірка ролі "статично" трохи спрощена. Що робити, якщо модератору заборонено редагувати публікацію іншого модератора? Чи не повинна ця перевірка бути частиною домену?
Réda Housni Alaoui

2
@ RédaHousniAlaoui Мені цікаво і про це. Я не можу придумати спосіб вирішення цього питання, крім того, щоб включити згадку про користувачів / модераторів у домені, або виконати якусь логіку в цьому ApiController, щоб отримати роль автора публікації. Жодне з них не здається правильним, і це є досить поширеною справою на моєму досвіді, що деякі чіткі вказівки були б надзвичайно корисними.
Джиммі

1
@Erwan, випадок використання, про який я говорю, динамічний. Подання речення "Автентифікація та авторизація є поганим прикладом для DDD" на привітних прикладах світу нечесно. DDD тут, щоб уникнути випадкових складностей і дозволити керувати складністю домену. Динамічні дозволи не є випадковою складністю, ані те, що не відбувається в реальному житті.
Réda Housni Alaoui

1
ІМХО, проблема вашого рішення полягає в тому, що він не задовольняє замовника. Замовник часто хоче мати можливість змінити ці відносини динамічно. Більше того, це також відбувається, коли постачальник надає одне і те ж програмне забезпечення підприємства для різних компаній. Якщо програмне забезпечення погано піддається виправленню, постачальник зрештою помре.
Réda Housni Alaoui

1
"Але це загальновизнано як" погану річ ". Ваші налаштування безпеки з часом стають некерованими, що фактично означає, що ваш додаток стає незахищеним". При правильному дизайні та тесті це повністю керовано. Але в моєму XP, щоб створити правильний дизайн, домен повинен перевірити дозвіл. Альтернатива - утопія.
Réda Housni Alaoui
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.