【问题标题】:ASP.NET Core Identity Authorization using Parameter for Team Membership使用团队成员资格参数的 ASP.NET Core 身份授权
【发布时间】:2018-07-01 09:29:18
【问题描述】:

我有一个包含如下表格的应用程序:

  • 用户(ASP.NET Core 身份)
  • 团队
  • UserTeam(多对多连接表)

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

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

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

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

【问题讨论】:

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


    【解决方案1】:

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

    尝试使用直接来自 ASP.NET Core Framework 的 IdentityRole

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

    【讨论】:

      【解决方案2】:

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

      然后,你需要把所有这些放在一起,并在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)
      { }
      

      现在您的行为仍然干净整洁。在这里,您可以通过将功能添加到您可以从处理程序调用的需求中来微调策略,或者做任何您想做的事情。

      【讨论】:

      • 唯一的问题是 authContext.HttpContext.Request.Query["teamId"] 返回 null。我将其更改为 authContext.RouteData.Values["teamId"] 并且有效。
      • 啊是的RouteData 会更健壮。我已经相应地更新了答案。
      • 关于 Asp.Net Core 3 的注释 - 由于端点路由 AuthorizationFilterContext 不再可用,资源类型为 Endpoint。如果您需要访问路由数据 IHttpContextAccessor 可以注入处理程序 - 根据这个问题中接受的答案 - stackoverflow.com/questions/59197631/…
      • context.Resource 始终是 Microsoft.AspNetCore.Http.DefaultHttpContext 类型,而不是 AuthorizationFilterContext,为什么以及如何解决? (.net 5.0)
      【解决方案3】:

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

      【讨论】:

        猜你喜欢
        • 2013-08-18
        • 1970-01-01
        • 1970-01-01
        • 2021-04-16
        • 2019-04-30
        • 2021-01-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多