Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multi-tenant Access Control: Repository or Service layer?

In a multi-tenant ASP.NET MVC application based on Rob Conery's MVC Storefront, should I be filtering the tenant's data in the repository or the service layer?

1. Filter tenant's data in the repository:

public interface IJobRepository
{
    IQueryable<Job> GetJobs(short tenantId);
}

2. Let the service filter the repository data by tenant:

public interface IJobService
{
    IList<Job> GetJobs(short tenantId);
}

My gut-feeling says to do it in the service layer (option 2), but it could be argued that each tenant should in essence have their own "virtual repository," (option 1) where this responsibility lies with the repository.

  • Which is the most elegant approach: option 1, option 2 or is there a better way?

Update:

I tried the proposed idea of filtering at the repository, but the problem is that my application provides the tenant context (via sub-domain) and only interacts with the service layer. Passing the context all the way to the repository layer is a mission.

So instead I have opted to filter my data at the service layer. I feel that the repository should represent all data physically available in the repository with appropriate filters for retrieving tenant-specific data, to be used by the service layer.

Final Update:

I ended up abandoning this approach due to the unnecessary complexities. See my answer below.

like image 774
Petrus Theron Avatar asked Apr 30 '10 14:04

Petrus Theron


2 Answers

@FreshCode, we do it in the repository, and we do not pass the tenant as a parameter. We use the following approach:

public IQueryable<Job> GetJobs()
{
    return _db.Jobs.Where(j=>j.TenantId == Context.TenantId);
}

The context is a dependency the repository has and that is created in the BeginRequest where you determine the tenant based on the url for example. I think in this way it's pretty transparent and you can avoid the tenantId parameter which may become a little bit disturbing.

Regards.

like image 102
uvita Avatar answered Nov 16 '22 00:11

uvita


Update: Not going with a multi-tenant approach cost me hundreds of hours in technical debt. Four years down the line, I wish I took the time to implement a clean tenant approach first. Don't make the same mistake!


Old, out-dated answer:

I ended up stripping out all multi-tenant code in favour of using separate applications and databases for each tenant. In my case I have few tenants that do not change often, so I can do this.

All my controllers, membership providers, role providers, services and repositories were gravitating toward duplicate .WithTenantID(...) code all over the place, which made me realize that I didn't really need one Users table to access data that is specific to one tenant 99% of the time, so using separate applications just makes more sense and makes everything so much simpler.

Thanks for your answers - they made me realize that I needed a redesign.

like image 28
Petrus Theron Avatar answered Nov 16 '22 01:11

Petrus Theron