繁体   English   中英

如何创建属性以检查用户是否对Identity Core 2.2拥有所有权?

[英]How can I create attribute to check if the user has a claim with Identity core 2.2?

我在ASP.NET Core 2.2框架的顶部有一个用C#编写的应用程序。

我希望能够在允许用户访问该操作之前检查用户是否有索赔。

我创建了一个AuthorizationHandler来检查用户是否有这样的声明

public class ClaimExistanceHandler : AuthorizationHandler<MustHaveClaimRequirement>
    {
        protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, MustHaveClaimRequirement requirement)
        {
            if (context == null
                || context.User == null
                || context.User.Identity == null
                || !context.User.Identity.IsAuthenticated
                || requirement == null
                || string.IsNullOrWhiteSpace(requirement.Type)
                || context.User.HasClaim(requirement.Type, requirement.Value))
            {
                context.Fail();

            }
            else
            {
                context.Succeed(requirement);
            }

            await Task.Yield();
        }
    }
}

那么要求如下

public class MustHaveClaimRequirement : IAuthorizationRequirement
{
    public string Type { get; set; }
    public string Value { get; set; }

    public MustHaveClaimRequirement(string type, string value)
    {
        Type = type;
        Value = value;
    }
}

但是,我怎样才能将此要求称为属性? 例如HasPermission("do something", "1")

似乎我的HasPermission类需要实现AuthorizeAttribute但不确定如何从该属性调用处理程序。

您的主要目标是将需求纳入策略中 ,然后使用或创建可以使用字符串名称指定该策略的属性。 完成此操作后,无需担心自己调用处理程序,因为ASP.NET Core会为您解决这一问题。

创建策略的最简单方法是在应用启动时执行此操作,如此处所述 创建策略,然后使用AuthorizeAttribute指定要附加到每个端点的策略。

但是,以这种方式进行操作需要您预先定义所有策略。 如果那将导致您需要创建大量不同的策略(因为您将要检查许多不同的索赔类型),而您真正想要的是能够拥有一个指定索赔信息的属性,更动态的方式:请参见此处 您需要创建一个AuthorizeAttribute实现,该实现将参数值(名称和类型) IAuthorizationPolicyProvider到字符串中,并创建并注册一个IAuthorizationPolicyProvider ,它可以解释该字符串并生成具有适当要求的策略。

编辑:还值得指出的是,ASP.NET Core已经包含了用于检查声明的需求实现: ClaimsAuthorizationRequirement AuthorizationPolicyBuilder有一个快捷方式( RequireClaim ),因此您可以快速创建检查声明的策略:

services.AddAuthorization(options =>
    {
        options.AddPolicy("EmployeeOnly", policy => policy.RequireClaim("EmployeeNumber"));
    });

首先,您需要注册保单及其相关声明:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();

    services.AddAuthorization(options =>
    {
        //Scenario 0: Policy requires Claim0 without care what the value is
        options.AddPolicy("MyPolicy0", policy => policy.RequireClaim("Claim0"));

        //Scenario 1: Policy requires Claim1 with value ClaimValue1_1 OR ClaimValue 1_2
        options.AddPolicy("MyPolicy1", policy => policy.RequireClaim("Claim1", "ClaimValue1_1", "ClaimValue1_2"));

        //Scenario 2: Policy requires Claims2 AND Claim3 with particular values
        options.AddPolicy("MyPolicy2", policy => {
            policy.RequireClaim("Claim2", "ClaimValue2");
            policy.RequireClaim("Claim3", "ClaimValue3"));
        }

        //Scenario 3: Policy requires Claims4 OR Claim5 with particular values
        options.AddPolicy("MyPolicy3", policy => {
            policy.RequireAssertion(ctx =>
            {
              return ctx.User.HasClaim("Claim4", "ClaimValue4") ||
                     ctx.User.HasClaim("Claim5", "ClaimValue5");
            })
        }
    });
}

然后在需要时应用这些检查(可以在控制器或操作级别应用):

[Authorize(Policy = "Policy1")]
public class HomeController : Controller
{

    [Authorize(Policy = "Policy2")]
    public ActionResult MyAction()
    {
       ...
    }

    [Authorize(Policy = "Policy3")]
    public ActionResult MyAnotherAction()
    {
       ...
    }

    [AllowAnonymous]
    public ActionResult NotSecuredAtAll()
    {
       ...
    }
}

别忘了,如果您将多个策略应用于一个控制器或操作,那么所有策略必须在授予访问权限之前通过(如果只有它们没有AllowAnonymous属性)。

有关ASP.NET Core 2.2中基于声明的授权的更多信息

在设法获取nlawalkerivamax9的反馈后,我设法编写了允许检查索赔存在的属性

总之, HasPermissionAttribute类采用claimType ,然后使用一个可选的claimValue创建一个策略名称。 属性类如下所示

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class HasPermissionAttribute : AuthorizeAttribute   
{
    public const string Policy_Prefix = "HasClaim";
    public const string Policy_Glue = ".";

    public HasPermissionAttribute(string type, string value = null)
    {
        Policy = GetPolicyValue(type, value);
    }

    private string GetPolicyValue(string type, string value)
    {
        if (string.IsNullOrWhiteSpace(type))
        {
            throw new ArgumentNullException($"{type} cannot be null.");
        }

        List<string> parts = new List<string> { type.Replace(Policy_Glue, "_").Trim() };

        if (!string.IsNullOrWhiteSpace(value))
        {
            parts.Add(value.Replace(Policy_Glue, "_"));
        }

        string policy = $"{Policy_Prefix}{Policy_Glue}{string.Join(Policy_Glue, parts)}";

        return policy;
    }
}

现在,我们已经通过HasPermissionAttribute应用了策略,我们现在需要采用已应用的策略,并使用AuthorizationPolicyBuilder注册该策略,以检查给定的声明是否存在。 也就是说,我添加了一个名为ClaimCheckerPolicyProvider的类,该类接受提供的声明并按如下方式处理检查

internal class ClaimCheckerPolicyProvider : IAuthorizationPolicyProvider
{
    public Task<AuthorizationPolicy> GetDefaultPolicyAsync()
    {
        return Task.FromResult(new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build());
    }

    public Task<AuthorizationPolicy> GetPolicyAsync(string policyName)
    {
        if (IsClaimBasePolicy(policyName))
        {
            string[] parts = GetParts(policyName);

            if (parts.Length > 0)
            {
                AuthorizationPolicyBuilder policy = GetPolicyBuilder(parts);

                return Task.FromResult(policy.Build());
            }
        }

        return Task.FromResult<AuthorizationPolicy>(null);
    }

    private bool IsClaimBasePolicy(string policyName)
    {
        return !string.IsNullOrWhiteSpace(policyName)
                        && policyName.StartsWith(HasPermissionAttribute.Policy_Prefix, StringComparison.OrdinalIgnoreCase);
    }

    private string[] GetParts(string policyName)
    {
        return policyName.Split(HasPermissionAttribute.Policy_Glue, StringSplitOptions.RemoveEmptyEntries)
                         .Where(x => !x.Equals(HasPermissionAttribute.Policy_Prefix))
                         .ToArray();
    }

    private AuthorizationPolicyBuilder GetPolicyBuilder(string[] parts)
    {
        if (parts == null)
        {
            throw new ArgumentNullException($"{nameof(parts)} cannot be null.");
        }

        var length = parts.Length;

        if (length == 0)
        {
            throw new ArgumentOutOfRangeException($"{nameof(parts)} cannot cannot be empty.");
        }

        var policy = new AuthorizationPolicyBuilder();

        if (length > 1)
        {
            return policy.RequireClaim(parts[0], parts[1]);
        }

        return policy.RequireClaim(parts[0]);
    }
}

最后,我们需要将提供程序注册为服务。 在Startup类的ConfigureServices中,添加以下内容

services.AddTransient<IAuthorizationPolicyProvider, ClaimCheckerPolicyProvider>();

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM