ASP.NET 5 Policy-Based Authorization Handle Not Being Called

I'm putting this here for reference because I spent way too long figuring this out...

I had implemented a custom requirement and handler (empty for testing's sake):

using Microsoft.AspNetCore.Authorization;
using System.Threading.Tasks;

public class TestHandler : AuthorizationHandler<TestRequirement>, IAuthorizationRequirement
{
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, TestRequirement requirement)
    {
        context.Succeed(requirement);
        return Task.CompletedTask;
    }
}

public class TestRequirement : IAuthorizationRequirement
{

}

Registered it in my Startup.cs ConfigureServices() section:

services.AddAuthorization(options =>
{
    options.AddPolicy("Test", policy => policy.Requirements.Add(new TestRequirement()));
    // Other policies here
}

Added it to my controller method:

[HttpGet]
[Authorize(Policy = "Test")]
public IActionResult Index()
{
    Return View();
}

But was getting a 403 error (not 401) with every request to the controller method!

Turns out, I was not registering TestHandler with the ConfigureServices() (Dependency Injection) section of Startup.cs.

services.AddSingleton<IAuthorizationHandler, TestHandler>();

Hope this saves someone from banging their head on their desk. :|


Take a look at Asp.net Core Authorize Redirection Not Happening i think adding options.AutomaticChallenge = true; solves your problem.


The answer to this question is alluded to in a comment to adem caglin, so props to him.

The issue is that the AuthorizeFilter is rejecting the request before the AuthorizationHandler is being called. This is because for every use of the Authorize tag MVC adds AuthorizeFilter ahead of the AuthorizationHandler in the pipeline. This AuthorizeFilter checks to see if any of the current users identities are authorized. In my case there were no authorized identities associated with any user so this would always fail.

A solution (which IMO is somewhat hackish) is to insert a peice of middleware that will get executed before any MVC code. This middleware will add a generic authenticated identity to a User (if the user does not already have one).

Consequently the AuthorizeFilter check will pass and the Handle method on the AuthenticationHandler method will be executed and our problem will be solved. The middleware code (which needs to be added to Configure before app.UseMvc(); is called) is as follows

    app.Use(async (context, next) =>
    {
        if (!context.User.Identities.Any(i => i.IsAuthenticated))
        {
            context.User = new ClaimsPrincipal(new GenericIdentity("Unknown"));
        }
        await next.Invoke();
    });

An alternative way to override the AuthorizeFilter is outline here (Override global authorize filter in ASP.NET Core MVC 1.0)

Citing the response from here (Asp.Net Core policy based authorization ends with 401 Unauthorized)