I'm working on implementing my first clean architecture and CQRS application, I've stumbled across a bit of logic that's leaving me a bit stumped. I'm working on integrating authorization and authentication into my application, but I'm having some trouble trying to figure out how to architect a portion of my application that will handle command validation. My system is multitenant and currently shares a database across all of my clients, and I need to implement some sort of system that will enable me to perform all of my verification in a way that is straightforward and not too tightly coupled.

In my system, I have a implementations for both Users and Clients. Users can belong to any number clients. These users also have varying levels of permissions granted to them (but this is managed by my roles systems and mostly irrelevant here). My WebAPI is designed in such a way that I limit authorization based on a fixed number of Roles and Claims. These largely remain static, so I don't need much flexibility here.

My main source of headache is determining "User-Client" interaction permissions. Namely, I want to determine if a user has access to client that they're attempted to update records for. One approach would be to add UserId to all of my commands and to individually check the permissions during each command and query. This seems tedious and prone to issues.

Another approach I considered was to define an interface or base class that merely added the client and user Ids to any object in which they were required, but this had the adverse affect of exposing those implementations to my WebAPIs (via swagger and the UserId/ClientId being a portion of the Request/Command object).

One final approach would be to make my underlying commands still implement those interfaces, but have my controller contain minimal logic to map an API request into one of my command objects. Again, this would be tedious and would start leaking my logic into my controllers.

Overall, it's as if I need some additional structure in my application in which I can pipe any object containing a ClientId into so that I can keep the Authentication and Authorization logic out of my core app. However, I'm mostly stumped, and I'm looking for ways that I can simplify my application by minimizing the overhead of adding client-dependent commands and queries.

If it's of any relevance, some of the core tools and technologies I'm leveraging are:

  • .Net Core 2.1
  • Mediatr
  • Entity Framework

And my core application implements commands in a similar fashion to:

public class CreateProductCommand : IRequest
{
    public int ClientId { get;set; }
    public int ParentProductId { get; set; }
    public string ProductName { get; set; }
    // other creation specific props here
}

public class CreateProductCommandHandler : IHandler<CreateProductCommand>
{
    public async Task<Unit> Handle(CreateProductCommand command)
    {
        // check parent permissions, make sure parent product
        // belongs to client who is entered. 
        // -----
        // rest of logic to save

        // -- Ideally the User-Client check would happen before
        // -- the command is ever sent to the handler, so that
        // -- only client-specific logic and permissions are checked.
        // -- As long as the user can edit the specific client, anything
        // -- that happens to the client is determined by standard business 
        // -- and domain logic.
    } 
}
  • Despite the title and the tags I don't see any Clean Architecture, or CQRS concerns here – candied_orange Nov 28 at 5:23
  • But why don't you get the current authenticated user from the session or similar? – Constantin Galbenu Nov 28 at 7:45
  • @ConstantinGalbenu I will very likely get the user from the session, my question is about finding a good approach to authorize a user in my business logic without explicitly including them in my commands. I don't want my users passing their own UserIds into my commands, but I also don't want 2 separate commands (one from the user to the api, and the api to the application layer). – JD Davis Nov 28 at 14:51
  • @JDDavis but why do you need to put the userId in the command if you can get it from the session? – Constantin Galbenu Nov 28 at 16:08
  • @ConstantinGalbenu my controller actions are incredibly slim and basically pipe commands directly to my application through mediatr like so: Task<IActionResult> Product(CreateProductCommand command) => Ok(_mediatr.Send(command);. I'm trying to keep as much logic out of my controller as possible. – JD Davis Nov 28 at 21:41
up vote 1 down vote accepted

Looks to me like your issue is:

I have a thread acting on behalf of a user. I don't wish to pollute my nice clean business logic with authorisation details. But my data store needs authorisation details to enforce control of the data.

From your description it sounds pretty critical that User A does/does not have access to Client B. That sounds very much like a Business Concern. So the first answer is its pretty obvious: Your business logic should care about which user is doing what. Passing the user details through the appropriate business logic directly is the clean way to handle this. This gives many positives: its clear, its clean, its easily tested, and the API is not coupled to the Data Store.

If need be there will be a point in your Business Logic where you can translate from talking about a User, to specifically talking about Authorised to do X. Also there is no reason why this User information could not be made more anemic, or enriched in different parts of your Business Logic.

Pragmatically, if the thread only serves one User at a time, use Thread Local storage and shove a reference to the user there. Later in your data store (aka wherever you need it) access that reference. This is a dreadful solution. It enforces direct coupling between API and Data Store (the recipient location), the Business Concern is not in the Business Logic, and you have a non-intuitive, indirect argument, that may not be set or cleaned up properly affecting future calls on the thread. In short what you make back from tedium, you will pay back over and over again in bugs and change resistance.


Added extra answer

Possible Solutions

  1. Attribute with some Aspect-Orientated programming.
  2. an Abstract Class/interface with some Aspect-Orientated programming.
  3. A Generic class that wraps a lambda/interface.
  4. a Meta Program that constructs an Abstract class for derivation.
  5. a Meta Program that constructs a tailored class which wraps a lambda/interface.

Solutions 1 and 2 uses your languages aspect orientation (C# attributes) to detect the "authorisation required" functions, and intercept calls to them. It will throw an exception on unauthorised, but permit the call if authorised.

class command
{
    public command(User user);

    public User user {get; }

    [AuthorisedFor("xyz")]
    public void action(object a);

    [AuthorisedFor("xyz")]
    public void action(User user, object a);
}

Solution 1 requires you to directly decorate the authorisation required functions, and provide an properties/arguments for user information.

Solution 2 allows you to pre-specify the authorisation required for the standard functions, and provide the properties/arguments for user information.

Solution 3 is a decorator and captures through its constructor the knowledge about authority required, the permit and deny functions. The only issue is that the Command interface will either force you to use Object arguments, a Generic Type and a limit on arguments, or require copies per downstream command interface.

class command<T>
{
    public command(User user, Authority[] required, Action<T> permit, Action<T> deny);

    public void action(T arguments);
}
class command2
{
    public command(Authority[] required, SomeInterface permit, SomeInterface2 deny);

    public void action();
}

Solutions 4 and 5 are just not easily achieved in C#. You would essential need to write code that JIT's a new Base Class and derivations, or decorator classes for the various interfaces. I only include them for completeness.

The run-time flexible options are 3 or 5. The other solutions 1, 2 or 4 are more reasonable for compile time.

User and Authorisation Passing

Orthogonal to which solution you pick for handling permit/deny, those solutions will need access to the user/authorisations. These could be stored in various forms of storage:

  • global
  • thread local
  • object property
  • function argument

Picking Global or thread local is going to give you the implicit user passing you desire, it will however complicate testing and be a source of non-intuitive bugs.

Picking an Object property or a function argument is going to require that you pass the user/authorisation information through your commands. It will make the information requirement explicit, simplify testing, and reduce the capacity for non-intuitive bugs. It will require more typing.

My preference is for explicitly passing the user/authorisations down. However there may be a reason that makes the implicit Global/Thread local option the better choice.

  • "From your description it sounds pretty critical that User A does/does not have access to Client B. " This is the quintessential difference between authentication and authorization. Authenticate to enter the restricted area (basic user login). Authorize any action taken within restricted area (business). – Neil Nov 28 at 7:57
  • Yes someone accessing the system would have to Authenticate that their Identity is indeed User A. Then and only then would their Authority be known to Permit or Deny particular Actions, and/or access to Data. The point is that for the Data Store to Permit or Deny it needs the Authenticated User's Authority, and perhaps even their Identity for auditing purposes. This necessitates that relaying and acting on this information is a concern of the code between the API and the Data Store. Excepting some edge-cases, that means a Business Concern implemented in Business Logic. – Kain0_0 Nov 28 at 8:33
  • I am perfectly fine with handling my authorization logic in the application layer, I'm just trying to find some strategy that allows me to authorize my users that doesn't require me to explicitly include the users in my command object. I'm envisioning some sort of interface that my commands can implement and have them go through a validator of sorts with the user being one parameter and the interface be the other. But I would also like it to be more of an automatic thing that simply runs on any command with that interface. – JD Davis Nov 28 at 14:53

Create IPermissionValidator that you inject from command's constructor using dependency injection. When you need to check permissions for CreateProduct you call _permissionValidator.ValidateCreateProduct(command.ParentProductId);. If user doesn't have permission it will throw exception PermissionValidationException that your web api will catch and return correct HTTP status code. If you need to way to check if user has permission and not throw, add _permissionValidator.TryValidateCreateProduct(command.ParentProductId); that returns bool true if it's valid. IPermissionValidator implementation can use dependency injection to get current user and validate accordingly.

This also makes your commands easily testable, because you can implement own IPermissionValidator for tests. You should tests all cases of validation in your commands.

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.