【问题标题】:How to do authorization based on groups in .net core app?如何在.net核心应用程序中基于组进行授权?
【发布时间】:2020-02-20 09:49:49
【问题描述】:

网络核心应用程序。我的要求是添加基于组的授权。我是 Azure AD 的用户。我属于一些以 BR 和 AR 开头的组名。只有属于 AR 组的用户才能访问我的 API。目前我的客户端应用程序是 Swagger,我只通过 swagger 访问 APIS。

例如,在启动时我可以有以下代码。

services.AddAuthorization(options => {
                options.AddPolicy("AR-BitBucket-User",
                        policyBuilder => policyBuilder.RequireClaim("groups",
                        "6be4f534-dcf5-489e-b57d-c7bb46be8d6b"));
            });  

在控制器中,

[Authorize("AR-BitBucket-User")]

在上述方法中,我是硬编码,但我不想硬编码。首先,我没有在 JWT 令牌中获取组信息,而我正在获取

hasGroups:true 在我的 JWT 令牌中。我想从 Graph API 中获取它,而不是硬编码。有人可以帮我怎么做吗?我无法在互联网上获得任何相关示例。那么有人可以帮助我吗?

【问题讨论】:

  • Startup.ConfigureServices 期间连接到graph api,获取数据并填充它。由于您在此阶段无法进行依赖注入,因此只需 new 它并将所需的访问数据传递给它。 [Authorize("AR-BitBucket-User")] 虽然不能轻易删除。但是使用它有点糟糕
  • 相反,您应该使用 ASP.NET Core Identity 的角色。将组放在那里并向组添加声明。当用户进行身份验证时,声明将分配给他。不太适合 jwt 身份验证,因为它的大小会增长并且不应该包含身份验证信息

标签: c# asp.net-core azure-active-directory authorization


【解决方案1】:

如果您想配置您的应用程序以接收组声明,您需要在 Manifest 文件中将“groupMembershipClaims”值设置为SecurityGroup

  1. 在应用程序注册门户上的应用程序设置页面中,单击“清单”以打开内联清单编辑器。

  2. 通过找到“groupMembershipClaims”设置并将其值设置为“SecurityGroup”来编辑清单。

  3. 保存清单。

    {
      ...
      "errorUrl": null,
      "groupMembershipClaims": "SecurityGroup",
      ...
    }

为应用程序启用组声明后,Azure AD 会在 JWT 和 SAML 令牌中包含一个声明,其中包含用户所属所有组的对象标识符 (objectId),包括传递组成员身份。

但请注意确保令牌大小不超过 HTTP 标头大小限制,Azure AD 限制它的 objectId 数量 包括在团体索赔中。如果用户是更多组的成员 超额限制(SAML 令牌为 150,JWT 令牌为 200),然后 Azure AD 不会在令牌中发出组声明。相反,它 在令牌中包含一个超额声明,表明 应用程序查询 Graph API 以检索用户的组 会员资格。更多详情请参考blog

所以你需要做一些处理:

  1. 检查声明_claim_names,其中一个值为组。这表示超龄。

  2. 如果找到,请调用 _claim_sources 中指定的端点以获取用户组。

  3. 如果找不到,请查看用户组的组声明。

当然,你也可以直接调用Microsoft Graph API来退出当前用户的群组不用使用group claims

关于如何根据该组进行授权,您可以创建策略。更多详情请参考document。例如

Startup.cs

    services.AddAuthorization(options =>
    {
        options.AddPolicy("CheckGroups", policy =>
            policy.Requirements.Add(new GroupsCheckRequirement("YourGroupID")));
    });
    services.AddScoped<IAuthorizationHandler, GroupsCheckHandler>();

GroupsCheckRequirement.cs:

    public class GroupsCheckRequirement : IAuthorizationRequirement
    {
        public string groups;

        public GroupsCheckRequirement(string groups)
        {
            this.groups = groups;
        }
    }

GroupsCheckHandler.cs:

    public class GroupsCheckHandler : AuthorizationHandler<GroupsCheckRequirement>
    {
        private readonly ITokenAcquisition tokenAcquisition;
        private readonly IMSGraphService graphService;

        public GroupsCheckHandler(ITokenAcquisition tokenAcquisition, IMSGraphService MSGraphService)
        {
            this.tokenAcquisition = tokenAcquisition;
            this.graphService = MSGraphService;
        }
        protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context,
                                                  GroupsCheckRequirement requirement)
        {
            string accessToken = await tokenAcquisition.GetAccessTokenOnBehalfOfUserAsync(new[] { Constants.ScopeUserRead, Constants.ScopeDirectoryReadAll });

            User me = await graphService.GetMeAsync(accessToken);

            IList<Group> groups = await graphService.GetMyMemberOfGroupsAsync(accessToken);

            var result = false;
            foreach (var group in groups)
            {
                if (requirement.groups.Equals(group.Id))
                {
                    result = true;
                }
            }

            if (result)
            {
                context.Succeed(requirement);
            }

        }


    }

然后使用策略:

[Authorize(Policy = "CheckGroups")] 

此外,您还可以通过 ASP.NET Core 中间件库来实现它。 asp.net 中间件通过在TokenValidationParametersRoleClaimType 属性中指定声明来支持从声明填充的角色。由于 groups 声明包含安全组的对象 ID 而不是实际名称,因此您将使用组 ID 而不是组名。更多详情请参考sample

Startup.cs

// The following lines code instruct the asp.net core middleware to use the data in the "groups" claim in the Authorize attribute and User.IsInrole()
            // See https://docs.microsoft.com/en-us/aspnet/core/security/authorization/roles?view=aspnetcore-2.2 for more info.
            services.Configure<OpenIdConnectOptions>(AzureADDefaults.OpenIdScheme, options =>
            {
                // Use the groups claim for populating roles
                options.TokenValidationParameters.RoleClaimType = "groups";
            });

然后使用它

[Authorize(Roles = “Group-object-id")] // In controllers
// or
User.IsInRole("Group-object-id"); // In methods

【讨论】:

  • 非常感谢您的回答。关于上述问题,我有几个问题。在我的 JWT 令牌中,我拥有 hasGroups 属性而不是声明 _claim_names 属性。所以我应该直接调用graph api对吗?
  • 也在startup.cs,policy.Requirements.Add(new GroupsCheckRequirement("YourGroupID")));而不是以这种方式进行硬编码,我们可以用其他方式来做吗?因为我有大约 100 个组。我无法对所有组 ID 进行硬编码
  • 目前,AAD JWT 令牌中不支持组名。
  • 我明白,但我们可以调用 Grph API 来获取正确的组名
  • 另外我很想知道 ITokenAcquisition 和 IMSGraphService 它们属于哪个命名空间?
猜你喜欢
  • 2020-03-19
  • 1970-01-01
  • 2019-10-13
  • 1970-01-01
  • 2020-04-30
  • 2021-04-16
  • 2023-03-13
  • 1970-01-01
  • 2019-04-17
相关资源
最近更新 更多