【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
是成功还是失败,最终结果都将是授权失败。