I am building sort of multi tenant application with shared tables using .NET Core 2.0 and EF Core.
I am also using generic repository together with Unit of Work if it matters.
I want to make it properly secured and also avoid repeating the logic, so I think if it's possible to somehow modify the DbContext which I am using to for every find operation add something like: entity => entity.tenantId == userContext.tenantId.
I also have to ensure that while creating the correct tenantId is applied and do not authorize update of other tenant property, but so far this logic is included in Service Layer - correct me if I am wrong with this approach?
The IUserContext is defined in Domain abstractions and the application layer implements it differently (API or Web App), but I am not sure if it is not code smell/anti pattern when data layer is doing this kind of logic? ( I am afraid it is).
Should this logic go to the Services (it will then have to be repeated many times which is not good idea I think), DbContext or should I adjust the repository in some way?
So what you want is that if someone would write some Linq statement like this
var result = myDbcontext.myDbSet.SomeLinq(...)
It would internally be like
var result = myDbContext.myDbSet
.Where(entity => entity.tenantId == userContext.tenantId)
.SomeLinq(...)
So what you should do, is that when users think that they access myDbContext.myDbSet, they actually get the subset where tenantId == userContext.tenantId
I think the neat solution would be to create a class that exposes an IQueryable for every DbSet in your DbContext and hides the actual DbContext.
Something like this:
class MyOriginalDbContext : DbContext
{
public DbSet<Student> Students {get; set;}
public DbSet<Teacher> Teachers {get; set;}
public DbSet<ClassRoom> ClassRooms {get; set;}
...
}
public MyLimitedContext : IDisposable
{
// to be filled in constructor
private readonly MyOriginalDbcontext dbContext = ...
private readonly int tenantId = ...
IQueryable<Student> Students
{
get
{
return this.dbContext.Students
.Where(student => student.tenantId == tenantId);
}
}
IQueryable<Student> Teachers
{
get
{
return this.dbContext.Teachers
.Where(teacher => teacher.tenantId == tenantId);
}
}
...
Users won't notice the difference:
using (var dbContext = new MyLimitedContext(...))
{
var TeachersWithTheirStudents = dbContext.Teachers
.Join(dbContext.Student)
.GroupBy(teacher => teacher.Id,
...
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With