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

ASP.NET Core Identity Authorization using Parameter for Team Membership

我有一个包含 table 的应用程序,如下所示:

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

我正在寻找一种方法来根据用户的团队及其在团队中的角色为用户授权控制器操作,这将作为声明添加或与单独的 RoleTeam table 一起添加。假设这样的控制器操作:

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

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

我希望你能重写你的会员实体类型:

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

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

ASP.NET Core 介绍了可以应用于 Authorize 属性的政策概念。像过滤器一样工作,但不需要编写过滤器。

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

首先,从 "requirement"

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

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

    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)
{ }

现在你的行为依然干净利落。从这里您可以通过向可以从处理程序调用的要求添加功能来微调策略,或者做任何您想做的事情。

在 Net Core 3 中,使用上面的以下答案, with comment listed

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