Резюме
Должна ли авторизация в CQRS / DDD реализовываться для каждой команды / запроса или нет?
Я впервые разрабатываю онлайн-приложение, использующее более или менее строго шаблон DDD CQRS. Я столкнулся с некоторой проблемой, которую я не могу понять.
Приложение, которое я создаю, представляет собой приложение главной книги, которое позволяет людям создавать книги, а также позволяет другим людям просматривать / редактировать / удалять их, например сотрудников. Создатель бухгалтерской книги должен иметь возможность редактировать права доступа к созданной бухгалтерской книге. Могли даже поменять владельца. Домен имеет две совокупности TLedger и TUser .
Я прочитал много постов с ключевым словом DDD / CQRS, касающихся безопасности, авторизации и т. Д. Большинство из них заявили, что авторизация была общим субдоменом , если только не создавалось приложение безопасности.
В этом случае основной домен - это, безусловно, учетная область, заинтересованная в транзакциях, балансировании и счетах. Но также требуется возможность управлять мелкозернистым доступом к бухгалтерским книгам. Мне интересно, как спроектировать это в терминах DDD / CQRS.
В учебниках DDD повсюду говорится, что команды являются частью вездесущего языка. Они значимы. Это конкретные действия, которые представляют «реальную вещь».
Поскольку все эти команды и запросы являются действительными действиями, которые пользователи будут выполнять в «реальной жизни», должна ли реализация авторизации сочетаться со всеми этими «командами» и «запросами»? Пользователь будет иметь полномочия для выполнения TLedger.addTransaction (), но не TLedger.removeTransaction (), например. Или пользователю будет разрешено выполнить запрос "getSummaries ()", но не "getTransactions ()".
Для определения прав доступа должно существовать трехмерное отображение в виде команды-пользовательской книги или запроса-главной книги.
Или, в отрыве, именованные «разрешения» будут зарегистрированы для пользователя. Разрешения, которые затем будут отображаться для конкретных команд. Например, разрешение «ManageTransactions» позволит пользователю выполнять «AddTransaction ()», «RemoveTransaction ()» и т. Д.
Разрешение сопоставления пользователя -> регистр -> команда / запрос
Разрешение сопоставления пользователя -> регистр -> разрешение -> команда / запрос
Это первая часть вопроса. Или вкратце, следует ли осуществлять авторизацию в CQRS / DDD для каждой команды или для запроса? Или авторизация должна быть отделена от команд?
Во-вторых, в отношении авторизации на основе разрешений. Пользователь должен иметь возможность управлять разрешениями в своих книгах или в тех книгах, которыми ему разрешено управлять.
- Команды управления авторизацией происходит в Главной книге
Я думал о добавлении событий / команд / обработчиков в агрегат Ledger , таких как grantPermission (), revokePermission () и т. Д. В этом случае применение этих правил будет происходить в обработчиках команд. Но для этого необходимо, чтобы все команды включали идентификатор пользователя, который выполнил эту команду. Затем я бы проверил в TLedger, существует ли разрешение для этого пользователя на выполнение этой команды.
Например :
class TLedger{
function addTransactionCmdHandler(cmd){
if (!this.permissions.exist(user, 'addTransaction')
throw new Error('Not Authorized');
}
}
- Команды управления авторизацией в Пользователе
Другой способ - включить разрешения в TUser. TUser будет иметь набор разрешений. Затем в обработчиках команд TLedger я получал пользователя и проверял, есть ли у него разрешение на выполнение команды. Но это потребовало бы от меня получения агрегата TUser для каждой команды TLedger.
class TAddTransactionCmdHandler(cmd) {
this.userRepository.find(cmd.userId)
.then(function(user){
if (!user.can(cmd)){
throw new Error('Not authorized');
}
return this.ledgerRepository.find(cmd.ledgerId);
})
.then(function(ledger){
ledger.addTransaction(cmd);
})
}
- Еще один домен с сервисом
Другая возможность - полностью смоделировать другой домен авторизации. Этот домен будет интересоваться правами доступа, авторизацией и т. Д. Субдомен учета будет использовать службу для доступа к этому домену авторизации в форме AuthorizationService.isAuthorized(user, command)
.
class TAddTransactionCmdHandler(cmd) {
authService.isAuthorized(cmd)
.then(function(authorized){
if (!authorized) throw new Error('Not authorized');
return this.ledgerRepository.find(cmd.ledgerId)
})
.then(function(){
ledger.addTransaction(cmd);
})
}
Какое решение будет наиболее "DDD / CQRS"?
источник
Ответы:
По первому вопросу я боролся с чем-то похожим. Я все больше склоняюсь к трехфазной схеме авторизации:
1) Разрешение на уровне команды / запрос «делает этот пользователь когда - либо разрешения на выполнение этой команды?» В приложении MVC это, вероятно, может быть обработано на уровне контроллера, но я выбираю общий предварительный обработчик, который будет запрашивать хранилище разрешений на основе текущего пользователя и выполняемой команды.
2) Авторизация внутри службы приложений «имеет ли этот пользователь» когда-либо * разрешение на доступ к этой сущности? »В моем случае это, вероятно, окажется неявной проверкой просто с помощью фильтров в хранилище - в моем домене это в основном это TenantId с немного большей детализацией OrganizationId.
3) Авторизация, которая зависит от временных свойств ваших объектов (таких как Статус), будет обрабатываться внутри домена. (Пример: «Только некоторые люди могут изменять закрытую бухгалтерскую книгу.») Я предпочитаю размещать это в домене, потому что это сильно зависит от домена и бизнес-логики, и мне не очень удобно показывать это в других местах.
Я хотел бы услышать ответы других на эту идею - разорвите ее на куски, если хотите (просто предоставьте несколько альтернатив, если вы это сделаете :))
источник
Я бы реализовал авторизацию как часть вашего BC авторизации, но развернул ее как фильтр действий в вашей системе Ledger. Таким образом, они могут быть логически отделены друг от друга - ваш код Ledger не должен вызывать код авторизации - но вы все равно получаете высокопроизводительную внутрипроцессную авторизацию каждого входящего запроса.
источник