简体   繁体   中英

Deciding to use Authorization or not on a per-request basis in Asp.net Core

I'm developing an ASP.net core MVC 2.2 app and at the moment I'm using the classic [Authorize] and [AllowAnonymous] attributes on my controller actions to decide whether a certain action can be accessed anonymously or requires authorization.

However, I have a requirement where certain actions should require authorization only if a certain header is missing from the http request. Usually I would implement this by simply having something like this:

[HttpGet]
[AllowAnonymous]
public IActionResult SomeAction()
{
    if (!Request.Headers.ContainsKey("something"))
    {
        return RedirectToAction("SomeActionWithAuth");
    }
    ...
}

[HttpGet]
[Authorize]
public IActionResult SomeActionWithAuth()
{
    ...
}

however, in this particular case I have a strict requirement to avoid redirects, so I cannot use this approach.

So my question is:

  • Is there a way to intercept the request before it reaches the controller and decide at runtime, on a per-request basis, if the request should require authentication or not?
  • If that is not possible, is there maybe a way to decide at runtime which controller/action to route the request to? (that way I could have a setup similar to the one above, with two actions with different auth requirements, but without causing an actual HTTP Redirect on the client side, which I cannot do)

Create your own authorisation policy to handle this.

public class HeaderRequirement : IAuthorizationRequirement
{
    public HeaderRequirement(string header)
    {
        Header = header;
    }

    public string Header { get; }
}

public class HeaderRequirementHandler : AuthorizationHandler<HeaderRequirement>
{
    protected override Task HeaderRequirementHandler (
        AuthorizationHandlerContext context,
        HeaderRequirement requirement)
    {
        var hasHeader = context.Request.Headers.ContainsKey(requirement.Header);
        if (hasHeader) // if we have the header
        {
            context.Succeed(requirement); // authorization successful
        }

        return Task.CompletedTask;
    }
}

Register the handler as a service

services.AddScoped<IAuthorizationHandler, HeaderRequirementHandler>();

Add the policy to the authorisation services

services.AddAuthorization(options =>
    {
        options.AddPolicy("SomeHeader", policy =>
            policy.Requirements.Add(new HeaderRequirement("SomeHeader")));
    });

Now you can use it like this: [Authorize(Policy = "SomeHeader")]

If you need it a little bit more dynamic, If you don't want to register every single header that could possible be authenticated but rather interpreted at run-time. You can write you own policy provider

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM