Fabio Cometti
Fabio Cometti

Reputation: 77

Dynamically add authorization to ASP.NET Core controller

I have a controller with some utility methods that I use in many internal projects. Until now I've always copied the source file in every project. Now I want to create a NuGet package for this controller to use in internal repository.

The problem is with the authorization for this controller. I don't want to put a specific [Authorize()] attribute on the controller class (or its actions) because the authorization should be chosen by the developer which use the package: in some project the controller can be used by everyone, in some project can be used only by authenticated users, in others can be used with a custom policy.

Any ideas on how to achieve the purpose?

Upvotes: 2

Views: 2428

Answers (1)

Métoule
Métoule

Reputation: 14472

I'd add the Authorize attribute with a forced policy, that all your users must implement. Something like this:

[Authorise(Policy = "MyLibPolicy")]
public class LibController : Controller
{
}

Then, based on their needs, they can declare it differently in their Configure method:

If they need authenticated users:

services.AddAuthorization(options =>
{
    options.AddPolicy("MyLibPolicy", policy =>
    {
        policy.RequireAuthenticatedUser();
    });
});

If they need a custom policy:

services.AddAuthorization(options =>
{
    options.AddPolicy("MyLibPolicy", policy =>
    {
        policy.RequireAuthenticatedUser();
        policy.RequireRole("SomeRole");
        // other requirements
    });
});

If they want anonymous access:

Now, that's the tricky part, because you can't create an empty policy (a policy requires at least one requirement).

You can, however, create your own custom requirement (in your Nuget package) to allow anonymous users (basically, a requirement that always succeed).

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

Then, your users will need to register it before using it, like this:

services.AddScoped<IAuthorizationHandler, AllowAnonymousAuthorizationRequirement>();
services.AddAuthorization(options =>
{
    options.AddPolicy("MyLibPolicy", policy =>
    {
        policy.AddRequirements(new AllowAnonymousAuthorizationRequirement());
    });
});

Upvotes: 8

Related Questions