【ASP.NET Core 授权】案例

自定义Requirement案例

单个Handler

public class MinimumAgeRequirement : AuthorizationHandler<NameAuthorizationRequirement>, IAuthorizationRequirement
{

    public MinimumAgeRequirement(int minimumAge)
    {
        MinimumAge = minimumAge;
    }

    public int MinimumAge { get; private set; }

    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, NameAuthorizationRequirement requirement)
    {
        if (context.User != null && context.User.HasClaim(c => c.Type == ClaimTypes.DateOfBirth)
        {
            var dateOfBirth = Convert.ToDateTime(context.User.FindFirst(c => c.Type == ClaimTypes.DateOfBirth).Value);
            int calculatedAge = DateTime.Today.Year - dateOfBirth.Year;
            if (dateOfBirth > DateTime.Today.AddYears(-calculatedAge))
            {
                calculatedAge--;
            }
            if (calculatedAge >= requirement.MinimumAge)
            {
                context.Succeed(requirement);
            }
        }
        return Task.CompletedTask;
    }
}

然后就可以直接在AddPolicy中使用了:

services.AddAuthorization(options =>
{
    options.AddPolicy("Over21", policy => policy.Requirements.Add(new MinimumAgeRequirement(21)));
});

怎么表示授权成功或失败?
在方法处理方法 HandleRequirementAsync 中,调用

//授权成功
context.Succeed(requirement);
//授权失败
context.Fail();

多Handler模式

授权策略中的多个Requirement,它们属于 & 的关系,只用全部验证通过,才能最终授权成功。但是在有些场景下,我们可能希望一个授权策略可以适用多种情况,比如,我们进入公司时需要出示员工卡才可以被授权进入,但是如果我们忘了带员工卡,可以去申请一个临时卡,同样可以授权成功:

public class EnterBuildingRequirement : IAuthorizationRequirement
{
}

public class BadgeEntryHandler : AuthorizationHandler<EnterBuildingRequirement>
{
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, EnterBuildingRequirement requirement)
    {
        if (context.User.HasClaim(c => c.Type == ClaimTypes.BadgeId)
        {
            context.Succeed(requirement);
        }
        else
        {
            // context.Fail();
        }
        return Task.CompletedTask;
    }
}

public class HasTemporaryStickerHandler : AuthorizationHandler<EnterBuildingRequirement>
{
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, EnterBuildingRequirement requirement)
    {
        if (context.User.HasClaim(c => c.Type == ClaimTypes.TemporaryBadgeId)
        {
            context.Succeed(requirement);
        }
        return Task.CompletedTask;
    }
}

如上,我们定义了两个Handler,但是想让它们得到执行,还需要将其注册到DI系统中:

services.AddSingleton<IAuthorizationHandler, BadgeEntryHandler>();
services.AddSingleton<IAuthorizationHandler, HasTemporaryStickerHandler>();

此时,在我们的应该程序中使用EnterBuildingRequirement的授权时,将会依次执行这两个Handler。而在上面介绍AuthorizationOptions时,提到它还有一个InvokeHandlersAfterFailure属性,在这里就派上用场了,只有其为true时(默认为True),才会在当前AuthorizationHandler授权失败时,继续执行下一个 AuthorizationHandler

在上面的示例中,我们使用context.Succeed(requirement)将授权结果设置为成功,而失败时并没有做任何标记,正常情况下都是这样做的。但是如果需要,我们可以通过调用context.Fail()方法显式的将授权结果设置为失败,那么,不管其他AuthorizationHandler是成功还是失败,最终结果都将是授权失败。

posted @ 2021-02-13 18:25  .Neterr  阅读(665)  评论(0编辑  收藏  举报