Где проверить авторизацию для команды?
Заголовок вопроса возобновляется в значительной степени: где я могу подтвердить авторизацию для команды?
Например, установка клиента как предпочтительного включает в себя:
-
MarkAsPreferred
действие контроллера (может быть Winforms или что-то еще);
-
SetCustomerAsPreferredCommand
;
-
SetCustomerAsPreferredCommandHandler
;
-
Customer.MarkAsPreferred()
(домен);
Я определил 3 места для проверки авторизации:
- пользовательский интерфейс для отображения целей (пользователь не должен видеть ссылку/кнопку, если у него нет доступа к ней);
- действие контроллера, чтобы подтвердить, что пользователь имеет право называть эту команду; команды считаются всегда успешными (в отношении проверки, но я тоже принимаю авторизацию), и у нас есть возможность сообщить пользователю об отсутствии доступа;
- внутри команды непосредственно перед вызовом логики домена;
SomeView.cshtml
if (authorizationService.Authorize("MarkCustomerAsPreferred))
{
// show link
}
CustomerController
[HttpPost]
public ActionResult MarkAsPreferred(Guid id)
{
if (!authorizationService.Authorize("MarkCustomerAsPreferred))
{
return RedirectToAction("Unauthorized");
}
var MarkCustomerAsPreferredCommand { Id = id };
...
}
MarkCustomerAsPreferredCommandHandler
public void Handle(MarkCustomerAsPreferredCommand command)
{
if (!authorizationService.Authorize("MarkCustomerAsPreferred"))
{
throw new Exception("...");
}
customer.MarkAsPreferred();
}
Мой вопрос: нужна ли мне проверка авторизации в 3-х местах или я просто переоценен?
Я искал по всему Интернету, но не смог найти ни одного примера или ссылки об этом.
Edit
После большего количества исследований и некоторых тестов, я думаю, что для добавления поведения (авторизации, проверки, регистрации), как предложил Деннис Тауб, проще и понятнее реализовать.
Я нашел этот пост в блоге, который объясняет именно эту концепцию.
О наличии нескольких обработчиков для одной команды, мне не нужно реализовывать один обработчик команд для каждого поведения для каждой исходной команды, одна команда обертки может обернуть все обработчики.
Ответы
Ответ 1
Я думаю, что окончательная авторизация должна выполняться на уровне службы приложений, т.е. как часть обработки команды. Например, можно обработать обработчик команд с помощью обработчика полномочий.
class AuthorizationHandler : IHandle<SetCustomerAsPreferred> {
IHandle<SetCustomerAsPreferred> innerHandler;
public AuthorizationHandler(IHandle<SetCustomerAsPreferred> handler)
{
innerHandler = handler;
}
public void Handle(SetCustomerAsPreferred command)
{
if (/* not authorized */)
throw ...
innerHandler.Handle(command);
}
}
class SetCustomerAsPreferredCommandHandler : IHandle<SetCustomerAsPreferred> {
public void Handle(SetCustomerAsPreferred command)
{
// do the work
}
}
Ответ 2
Хороший пользовательский интерфейс должен иметь эту проверку в представлении, поэтому пользователь не будет щелкать по ошибке. Я считаю проверку контроллера "реальной", потому что там создается команда. Если у пользователя нет прав, она не должна создавать (или даже достигать этого действия) команду.
Я считаю, что установка проверки в обработчике немного завышена, так как она не несет ответственности за авторизацию и не похожа на то, что пользователь может напрямую получить доступ к обработчику.