Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

TLDR;

Where and possibly how should I implement scope based logic in the example code?

I have got a ASP.NET Web Api.

The Api uses OData (on top off REST) for data endpoints and OAuth 2.0 authentication. Now I want to add functionality to handle an Access Token in several different scopes.

Some of the scopes are:

  • User
  • Organization
  • Customer

The result set the API returns should be based on this scope. The same applies if someone wants to add, update or delete an entity.

Now take for example the following endpoint:

http://myapi/Employees

Someone with a Token in the Organization scope does a GET and should only get the employees that are in the Organization that is defined within the Token. An user in the Customer scope should get the employees for all organizations within the customer defined in the Token. This functionality however is not available for someone with a Token in the User scope.

The same applies to a POST. Someone within the organization scope should only be allowed to add a new employee to his own organization.

The functionality for the different scopes will usually only differ a little bit. In the case of getting the employees the difference is only a where on organization or otherwise on customer. In the case of a post their should be a check to see if for example the organization is part of the customer that is bound to the customer Token.

Current implementation:

Currently we have a base ApiController which is generic typed. The base controller calls an Query or CommandHandler with the entity type and all the implementation details are inside this handlers.

ApiController

public abstract class ApiController<TEntity> : EntitySetController<TEntity, Guid>
    where TEntity : class, IApiEntity
{
    protected readonly IQueryProcessor QueryProcessor;
    protected readonly ICommandProcessor CommandProcessor;

    protected ApiController(IQueryProcessor queryProcessor, ICommandProcessor commandProcessor)
    {
        this.QueryProcessor = queryProcessor;
        this.CommandProcessor = commandProcessor;
    }

    [HttpGet]      
    public override IQueryable<TEntity> Get()
    {
        var command = new GetEntityCommand<TEntity>();
        return this.QueryProcessor.Process(command);
    }
}

EmployeeController

public class EmployeeController : ApiController<Employee>
{ }

GetEmployeeHandler

public class GetEmployeeCommandHandler : IQueryHandler<GetEntityCommand<Employee>, IQueryable<Employee>>
{
    public IQueryable<Employee> Handle(GetEntityCommand<Employee> command)
    {    
         // Code that knows how to get a collection of employees.
         // This collection contains all employees
    }
}   

PostEmployeeHandler

public class PostEmployeeCommandHandler : ICommandHandler<PostEntityCommand<Employee>, Employee>
{
   public Employee Handle(PostEntityCommand<Employee> command)
    {    
         // Code that knows how to add an employee to the database.
    }
} 

The question

Where and possibly how should I implement the scope based logic? I know there has to be a smart way to do this and a good place to implement this scope based logic, I just don't see it (yet).

share|improve this question

2 Answers 2

I think that at least part of the answer is to make your Access Token 'ambient', so that you can access it from any part of your code without having to pass it along as an argument with every call.

One of the ways to do this is to define a custom IPrincipal that includes your Access Token, and set it on the HttpContext.Current.User* , e.g. see this answer. In MVC, there is usually a filter that allows you to hook in at the correct point.
* If you do this early enough, the principal gets copied to the Thread.CurrentPrincipal automatically, otherwise you might have to set it manually.

Once you have this in place, you could use extension methods to do the scoping. For example, something like this:

public static IEnumerable<Employee> FilterToScope(this IEnumerable<Employee> employees)
{
    var token = (Thread.CurrentPrincipal as MyTokenPrincipal).Token;
    if(token.IsCustomerScoped)
    {
        //Filter employees on customer
    } else if //etc.
}
share|improve this answer
    
Thanks for your answer. I totally agree on making the Access Token 'ambient' I did so by adding all information on the Token as Claims to the ClaimsPrincipal that is set as the CurrentPrincipal for every request. I don't see however how the extension methods would fit in. Note that most controllers don't need a specific implementation. As a Query / Command is started based on entity type. I would like a solution that knows how to handle default cases (filter on customer based on an interface or something) and a specific implementation when needed. I just don't know how to do this good, yet. –  Jos Vinke Jul 27 at 20:08
    
I figured your problems were in the controllers, since that was the fragment you posted. Could you tell us a bit more about how your entities are modelled? –  Astrotrain Jul 28 at 7:06
    
Yes I'll update the question later today, I'll keep you posted. I'll make the question more generic which basically comes down to how to handle scopes / different query options / authorization? using command / query pattern. That is what is used in the controller if you look at the fragments I posted. The entities are all ViewModels by the way. –  Jos Vinke Jul 28 at 7:56

I strongly suggest that you put this scope logic inside your data schema design (SQL tables for example). Don't do filtering. The reason is mainly scalability.

  • When there are so many data items, you don't want to ask the DB to load them all, and then you apply scoping on these items in memory. You overload the DB with extra work, and memory too.
  • Database can query items with scoping parameters (query optimizers work very well for SQL) much better. You will have better speed.
  • Using the DB will also help you avoid lot of problems with transaction and concurrency.
share|improve this answer
    
Hey thanks for your answer, you certainly have a valid point. I don't know if you're familiar with LINQ but, all IQuery results are IQueryable. This means that the results are lazy loaded from the database. OData also utilizes this by sending query parameters from the requesting partner directly to the database. So wherever I hook a method into the chain off loading a IQueryable only the items that I need will be loaded from the database. Unfortunately this still leaves me with a problem when adding / updating and deleting items as well. If you have any other ideas / suggestions, please shoot! –  Jos Vinke Jul 27 at 19:57
    
@Jos Vinke That's good then, I saw the other answer suggesting filtering. I personally think that's not how you do it. Anyway, you seem to know more than me. Do what you see fit. –  InstructedA Jul 28 at 2:19

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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