我有一个服务,匿名用户可以检索https://myService.com/data?date={utc.yesterday}
的数据,但在某些情况下,只有经过身份验证的用户才允许检索https://myService.com/data?date={utc.today}
的数据。
基本上,管理员需要在匿名用户可以查看之前通过另一个API审核预览数据。审批不是此问题的重点。
如何设置授权策略,当我们的数据库指示此数据尚未获得批准时,就会出现挑战。在策略授权时是否可以强制进行身份验证?
我有一个服务,匿名用户可以检索https://myService.com/data?date={utc.yesterday}
的数据,但在某些情况下,只有经过身份验证的用户才允许检索https://myService.com/data?date={utc.today}
的数据。
基本上,管理员需要在匿名用户可以查看之前通过另一个API审核预览数据。审批不是此问题的重点。
如何设置授权策略,当我们的数据库指示此数据尚未获得批准时,就会出现挑战。在策略授权时是否可以强制进行身份验证?
如果要将控制器从身份验证过程中排除,可以使用allow anonymous属性:
[AllowAnonymous]
public class AnonymousController : ControllerBase
{
}
我最近正在做类似的事情,并成功使用自定义授权处理程序实现了它。AllowAnonymous告诉aspnet core忽略Authorize属性,但它也会消除一个默认要求叫做DenyAnonymousAuthorizationRequirement。所以我不能使用AllowAnonymous,但是在我的自定义策略处理程序中,如果满足我的标准,我也会将DenyAnonymousAuthorizationRequirement标记为成功。这样就可以允许未经身份验证的用户通过,当用户满足授权要求时返回401。
[Authorize(Policy = "IsResourceApprovedToView")]
public class MyResourceController : ControllerBase
{
}
public sealed class IsResourceApprovedToViewRequirement : IAuthorizationRequirement {}
public sealed class IsResourceApprovedToViewAuthorizationHandler : AuthorizationHandler<IsResourceApprovedToViewRequirement>
{
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, IsResourceApprovedToViewRequirement requirement)
{
// Look up whatever you need with classes injected through handler constructor. You can use var httpContext = context.Resource as DefaultHttpContext; if you did not specify a resource type to get route data
if (isApproved)
{
context.Succeed(requirement);
// Now allow anonymous
var denyAnonymousUserRequirements = context.PendingRequirements.OfType<DenyAnonymousAuthorizationRequirement>();
foreach (var denyAnonymousUserRequirement in denyAnonymousUserRequirements)
{
context.Succeed(denyAnonymousUserRequirement);
}
}
else
{
context.Fail(new AuthorizationFailureReason(this, "Not approved"));
}
}
}
DI:
services.AddScoped<IAuthorizationHandler,IsResourceApprovedToViewAuthorizationHandler>(); // Add scoped if you need scoped services injected into your handler - otherwise AddSingleton
services.AddAuthorization(o => o.AddPolicy("IsResourceApprovedToView", new AuthorizationPolicyBuilder().AddRequirements(new IsResourceApprovedToViewRequirement()).Build()));
services.AddAuthorization(config =>
config.AddPolicy("PolicyName",
policyBuilder => policyBuilder.RequireAssertion(context => true) ));
类似的情况是当登录端点在某些条件下无法执行(系统正在维护或浏览器不受支持)。
我创建了一个自定义的AuthorizationHandler,根据上下文执行不同的检查,查询数据库,然后调用上下文对象上的Succeed或Fail方法。
[Authorize(Policy = nameof(LoginRequirement))]
public class LoginController : ControllerBase
{
}
public sealed class LoginRequirement : IAuthorizationRequirement { }
public class LoginAuthorizationHandler : AuthorizationHandler<LoginRequirement>
{
private LoginService _service;
public LoginAuthorizationHandler(LoginService service) {
_service = service;
}
public override async Task HandleAsync(AuthorizationHandlerContext context) {
if (!context.PendingRequirements.Any(req => req is LoginRequirement)) {
await base.HandleAsync(context);
return;
}
var httpContext = (HttpContext)context.Resource;
if (_service.CheckLoginConstraints(httpContext)) {
var requirement = context.PendingRequirements.First();
context.Succeed(requirement);
} else {
context.Fail();
}
}
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, LoginRequirement requirement)
{
var httpContext = (HttpContext)context.Resource;
if (_service.CheckLoginConstraints(httpContext)) {
context.Succeed(requirement);
} else {
context.Fail();
}
}
}