I have an application with tables like this:
Users can be mem
ASP.NET Core introduces the concept of policies that you can apply to your Authorize
attribute. works like filters, but without writing filters.
Each policy has one or more requirements that must all be met for the policy to pass. The Microsoft docs have a good example of setting up policies. In your case I'd do something like the following:
First, start with a "requirement"
public class TeamAccessRequirement : IAuthorizationRequirement
{
}
Then add a requirement handler
public class TeamAccessHandler : AuthorizationHandler<TeamAccessRequirement>
{
private readonly DbContext dbContext;
public TeamAccessHandler(DbContext dbContext)
{
// example of an injected service. Put what you need here.
this.dbContext = dbContext;
}
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, TeamAccessRequirement requirement)
{
// pattern matching is cool. if you can't do this, use context.Resource as AuthorizationFilterContext before and check for not null
if (context.Resource is AuthorizationFilterContext authContext)
{
// you can grab the team id, (but no model builder to help you, sorry)
var teamId = Guid.Parse(authContext.RouteData.Values["teamId"]);
// now you can do the code you would have done in the guts of the actions.
if (context.User.IsTeamAdmin(teamId))
{
context.Succeed(requirement);
}
else
{
context.Fail();
}
}
return Task.CompletedTask;
}
}
Then, you need to put this all together and enable it in the Startup.cs
under ConfigureServices
, like this:
services.AddAuthorization(options =>
{
options.AddPolicy("HasAdminTeamAccess", policy =>
policy.Requirements.Add(new TeamAccessRequirement()));
});
services.AddTransient<IAuthorizationHandler, TeamAccessHandler>();
And finally, the usage:
[HttpGet]
[Authorize(Policy = "HasAdminTeamAccess")]
public IActionResult ManageTeam(Guid teamId)
{ }
Now your actions remain nice and clean. From here you can fine tune the policy by adding functionality to the requirements that you can call from the handler, or do whatever you want.
I hope you can rewrite your membership entity types:
Try using IdentityRole which comes directly from the ASP.NET Core Framework.
https://docs.microsoft.com/en-us/aspnet/core/security/authorization/roles
In Net Core 3, use the following answer above, https://stackoverflow.com/a/48390808/14727392 with comment listed "context.Resource as AuthorizationFilterContext" returning null in ASP.NET Core 3.0
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, CookieOrTokenAuthorizationRequirement requirement)
{
if (context.Resource is Endpoint endpoint)
{
if endpoint.Metadata.OfType<AuthorizeAttribute>().Any(filter=> filter.Policy == "HasAdminTeamAccess")
var teamId = _httpContextAccessor.HttpContext.GetRouteData().Values["teamId"]
if (context.User.IsTeamAdmin(teamId))
{
context.Succeed(requirement);
}
else
{
context.Fail();
}
}
}