I'm using EF Core 3.0 and I like to implement a ABAC system to control rights in my app. To do it I'd like to do all the permissions stuff in just one layer and control it using some decorators in the controllers. The idea is to follow a bit this example. I think using the new UseAuthorization
method will be also helpful.
I am still designing the solution and I have an issue: currently in my controllers I have functions such as (the AuthorisationFilter is not implemented yet, it's precisely where I'm working on)
// GET api/project/:id
[HttpGet("{projectId}")]
[AuthorisationFilter]
public async Task<ProjectDTO> GetProjectById(int projectId)
{
return await this.projectService.GetProject(projectId);
}
and I also have some others that return all projects:
// GET api/project/projects
[HttpGet("projects")]
[AuthorisationFilter]
public async Task<IEnumerable<ProjectDTO>> GetAllProjects()
{
return await this.projectService.GetAllProjects();
}
Now, in my first case, my authorization filter should simply consider according to some attributes if a certain user is able to access this project or not. Clear.
However, in the second case, it could be that one user can see some projects and a different user can see some different projects, and I don't know exactly what my authorisation filter should return. Allow or deny? If I deny, I lose control of what happens next.
I understand the authorisation filter is not the place to create the conditions to generate the SQL query, but I don't like either to simply accept the action and lose control of the permissions. In other words: if there is a bug in the implementation of GetAllProjects
which returns more projects than the authoirised ones, I should not send these projects to the user.
Hence: how should the authorisation layer work? Should I filter there the valid projectId's and then call GetAllProjects
with this list as an argument?
In a nutshell: is there a way put all the rights control in a single layer?
Authorization layer should provide details about what the user can do, but enforcing that is up to the individual components.
Your ProjectService
need to know what the user is authorized to do and enforce it.
If your authorization layer decides that, it can become very involved in pretty much everything your application does, as it need to know way too much about each controller action or the database access, or whatever else which will not be very maintainable.
What if one of your services decides to access a 3rd party service over a 3rd party SDK?, it would make sense for your ..say MyTwitterService
to enforce that rather than a generic authorization layer.
Usually you pass in the context of the user (usually some sort of "rights" the user has) and the ProjectService
will decide what things to return. (or fail if the rights are insufficient or invalid).