API – How to handle scope based functionality?

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).

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.

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.
}

3

I would recommend not to return different information on the same URI based on user’s scope.

It’s better to validate a set of parameters a client passes to the service against scopes he authorized. REST identifies a resource or resources via its URI. and it looks to me to be against REST principles to return different sets of information via the same URI.

So, in your code just make sure the client requesting http://myapi/Employees/?organization=xyz has scope organization_xyz before returning anything to him.

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật