Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Where to verify authorization for a Command?

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:

  • UI for displaying purposes (user should not see a link/button if he/she does not have access to it);
  • controller action to verify the user is authorized to call that command; commands are assumed to always succeed (regarding validation, but I'm assuming authorization too) and we have a chance to inform the user about lack of access;
  • inside the command just before calling domain logic;

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.

like image 928
Luiz Damim Avatar asked Jun 18 '13 02:06

Luiz Damim


1 Answers

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
    }

}
like image 80
Dennis Traub Avatar answered Oct 31 '22 09:10

Dennis Traub