How to check ASP.NET auth policy in code rather than using AuthorizeAttribute?

Viewed 122

The normal way to check that a policy is being fulfilled in ASP.NET Core's authorization system is to setup a policy in ConfigureServices like so:

services.AddAuthorization(conf => {
    conf.AddPolicy("UserHasRecentPassport", policy => policy.RequireAssertion(ctx => { return ctx.User.HasRecentPassport(); }));
}

... and then specify it for a controller or action using AuthorizeAttribute, like so:

[Authorize("UserHasRecentPassport")]
public class HomeController : Controller {
    public IActionResult Index() {
        return View();
    }
}

However, I'm writing a tag helper which needs to check whether a particular policy is being met. I therefore need to just check this in code rather than using the AuthorizeAttribute approach, ie. something like:

public override void Process(TagHelperContext context, TagHelperOutput output) {
    output.TagName = null;
    if (!policyRequirementIsMet("UserHasRecentPassport")) {
        output.SuppressOutput();
    }
}

Is there any way for me to implement policyRequirementIsMet so it goes to ASP.NET Core and says "tell me whether the policy with name X is met"?

1 Answers

Use IAuthorizationService to perform imperative authorization. It is a little more involved than shown in the docs when used inside of a TagHelper class since they don't have direct access to HttpContext and User.

Here's one approach that uses the [ViewContext] attribute as a means to get hold of HttpContext and User, and uses DI to get hold of IAuthorizationService:

public class PassportTagHelper : TagHelper
{
    private readonly IAuthorizationService authorizationService;

    public PassportTagHelper(IAuthorizationService authorizationService)
    {
        this.authorizationService = authorizationService;
    }

    [ViewContext]
    public ViewContext ViewContext { get; set; }

    public override async Task ProcessAsync(TagHelperContext ctx,
        TagHelperOutput output)
    {
        var httpContext = ViewContext.HttpContext;
        var authorizationResult = await authorizationService
            .AuthorizeAsync(httpContext.User, "UserHasRecentPassport");

        if (!authorizationResult.Succeeded)
            output.SuppressOutput();
    }
}

Things to note:

  • HttpContext is accessed via the ViewContext property, which is set courtesy of decorating it with the [ViewContext] attribute.
  • Process changes to ProcessAsync, so that we can use await.
  • The value returned from AuthorizeAsync is an AuthorizationResult, which indicates success via its Succeeded property and a reason for failure in its Failure property.
Related