使用参数进行团队成员身份的ASP.NET核心身份授权

时间:2018-01-22 17:10:57

标签: c# asp.net-core asp.net-core-identity

我有一个像这样的表的应用程序:

  • 用户(ASP.NET核心身份)
  • UserTeam(多对多连接表)

用户可以是多个团队的成员,并且可以在团队中拥有不同的角色。例如,用户可能是TeamA的TeamAdmin,但只是TeamB的普通成员。因此,使用静态值定义的简单角色检查和策略将不起作用。

我正在寻找一种方法来根据用户的团队及其在团队中的角色为用户授权控制器操作,这些操作既可以作为声明添加,也可以作为单独的RoleTeam表添加。假设Controller的动作如下:

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

我需要验证用户是否具有相关团队的TeamAdmin角色。是否有一种干净的方法来使用可以访问teamId参数的Authorize属性来装饰它?或者我是否必须在if (User.IsTeamAdmin(teamId) ...语句中包含所有这些操作的内容?

3 个答案:

答案 0 :(得分:10)

ASP.NET Core引入了可应用于Authorize属性的策略概念。像过滤器一样工作,但没有编写过滤器。

每个策略都有一个或多个要求,必须满足要求才能传递的策略。 Microsoft docs有一个很好的设置政策的例子。在您的情况下,我会执行以下操作:

首先,从"要求"

开始
public class TeamAccessRequirement : IAuthorizationRequirement
{
}

然后添加需求处理程序

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;
    }
}

然后,您需要将所有内容放在一起并在Startup.cs ConfigureServices下启用它,如下所示:

    services.AddAuthorization(options =>
    {
        options.AddPolicy("HasAdminTeamAccess", policy =>
            policy.Requirements.Add(new TeamAccessRequirement()));
    });

    services.AddTransient<IAuthorizationHandler, TeamAccessHandler>();

最后,用法:

[HttpGet]
[Authorize(Policy = "HasAdminTeamAccess")]
public IActionResult ManageTeam(Guid teamId)
{ }

现在你的行动保持干净整洁。从这里,您可以通过向可以从处理程序调用的需求添​​加功能来微调策略,或者执行您想要的任何操作。

答案 1 :(得分:0)

我希望您可以重写您的会员实体类型:

尝试使用直接来自ASP.NET核心框架的 IdentityRole

https://docs.microsoft.com/en-us/aspnet/core/security/authorization/roles

答案 2 :(得分:0)

在Net Core 3中,使用上面的以下答案,https://stackoverflow.com/a/48390808/14727392,并列出"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();
        }
    }
}