ASP.NET Core Identity Authorization using Parameter for Team Membership

做~自己de王妃 提交于 2019-12-20 14:20:49

问题


I have an application with tables like this:

  • User (ASP.NET Core Identity)
  • Team
  • UserTeam (many-to-many join table)

Users can be members of multiple teams, and can have different Roles within the teams. For example a User may be a TeamAdmin for TeamA but just a normal member of TeamB. Because of this, simple Role checks and Policies defined with static values won't work.

I'm looking for a way to authorize Controller Actions for Users based on their Team and their role in the Team, which will either be added as a Claim or with a separate RoleTeam table. Assuming a Controller action like this:

[HttpGet]
[Authorize(???)]
public IActionResult ManageTeam(Guid teamId)
{ }

I would need to verify that the User has the TeamAdmin Role for the Team in question. Is there a clean way to decorate it with an Authorize attribute that can access the teamId parameter? Or will I have to wrap the guts of all of these Actions in if (User.IsTeamAdmin(teamId) ... statements?


回答1:


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.




回答2:


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



来源:https://stackoverflow.com/questions/48386853/asp-net-core-identity-authorization-using-parameter-for-team-membership

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!