I have an .NET Core 3 WebAPI where I want to use custom policy-based authorization, where one of the policies has multiple requirements.
I have added the policy in Startup.ConfigureServices()
and added MyCustomPolicyHandler
to DI:
public virtual void ConfigureServices(IServiceCollection services)
{
services.AddAuthorization(options =>
{
options.AddPolicy("MyCustomPolicy", policy =>
{
policy.Requirements.Add(new RequirementA());
policy.Requirements.Add(new RequirementB());
policy.Requirements.Add(new RequirementC());
policy.Requirements.Add(new RequirementD());
});
services.AddScoped<IAuthorizationHandler, MyCustomPolicyHandler>();
});
}
I have implemented MyCustomPolicyHandler
using the example from this documentation:
Policy-based authorization in ASP.NET Core
public class MyCustomPolicyHandler: IAuthorizationHandler
{
public Task HandleAsync(AuthorizationHandlerContext context)
{
var pendingRequirements = context.PendingRequirements.ToList();
Console.WriteLine($"MyCustomPolicyHandler: {pendingRequirements.Count} requirements");
foreach (var requirement in pendingRequirements)
{
if(requirement is RequirementA) {
// do stuff to check the requirements
context.Succeed(requirement);
}
else if(requirement is RequirementB) {
// do stuff to check the requirements
context.Succeed(requirement);
}
else if(requirement is RequirementC) {
// do stuff to check the requirements
context.Succeed(requirement);
}
else if(requirement is RequirementD) {
// do stuff to check the requirements
context.Succeed(requirement);
}
}
return Task.CompletedTask;
}
}
Next, I apply the policy to one of the controller actions:
public class MyController
{
[HttpGet]
[Authorize(Policy="MyCustomPolicy")]
public ActionResult<SomeViewModel> Get(int id) {
// do stuff
return Ok(vm);
}
}
The problem I'm encountering is there are no requirements associated with the policy. The Console.WriteLine()
message shows 0 requirements:
MyCustomPolicyHandler: 0 requirements
If I move the policy to the controller, the requirements are present:
[Authorize(Policy="MyCustomPolicy")]
public class MyController
{
[HttpGet]
public ActionResult<SomeViewModel> Get(int id) {
// do stuff
return Ok(vm);
}
}
MyCustomPolicyHandler: 4 requirements
However, I need this policy applied to the action, not the controller. The [Authorize(Policy="MyCustomPolicy")] attribute should work at the action level.
Any idea why this isn't working?
Thanks.
Because the place where MyCustomPolicyHandler
is injected is misplaced. It needs to be placed outside of AddAuthorization
.
services.AddAuthorization(options =>
{
options.AddPolicy("MyCustomPolicy", policy =>
{
policy.Requirements.Add(new RequirementA());
//...
});
});
services.AddScoped<IAuthorizationHandler, MyCustomPolicyHandler>();