The question's title resumes pretty much: where do I verify authorization for a Command?
For example, setting a customer as preferred involves:
MarkAsPreferred
controller action (could be Winforms or whatever);SetCustomerAsPreferredCommand
;SetCustomerAsPreferredCommandHandler
;Customer.MarkAsPreferred()
(domain);I identified 3 places to check for authorization:
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();
}
My question is: Do I need to verify authorization in 3 places or I'm just being overzealous?
I searched all over the internet but couldn't find any example or reference about this.
Edit
After more research and some tests I think wrapping the commands to add behavior (authorization, validation, logging) as Dennis Taub suggested is easier and cleaner to implement.
I found this blog post which explains exactly this concept.
About having multiple handlers for one command, I don't need to implement one command handler for each behavior for each original command, one wrapping command can wrap all handlers.
I think final authorization should be done on the application service level, i.e. as part of handling the command. You could wrap the command handler with an authorization handler for example.
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
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With