Home > Software design >  Secure ASP controllers/methods programmatically
Secure ASP controllers/methods programmatically

Time:04-26

I'm after the API that allows to apply [Authorize] attribute from API rather than having it on controller's class/method.

Consider third party controller classes that come from dependency nuget package and I want to host them in my application and implement security for them. I know I can use

app.UseEndpoints(endpoints => { endpoints.MapControllers().RequireAuthorization(new AuthorizeAttribute("policy")); });

but this will configure ALL controllers and methods to be protected by policy and I need to have control per class/method. Mapping manually with

 endpoints.MapPut("***").RequireAuthorization(new AuthorizeAttribute("someOtherPolicy"))

is also not an option since the mapping is already defined with [Microsoft.AspNetCore.Mvc.HttpPost, Microsoft.AspNetCore.Mvc.Route("api/someRoute")] attributes on imported controllers.

Please advise

CodePudding user response:

In case you can determinate on which endpoint should be specific authorization policy applied, you can try following:

public class MyAuthorizationFilter: AuthorizeAttribute, IAsyncAuthorizationFilter
{
    public MyAuthorizationFilter() : base()
    {
        //this.AuthenticationSchemes = "";
        //this.Policy = "";
        //this.Roles = "";
    }

    public Task OnAuthorizationAsync(AuthorizationFilterContext context)
    {
        context.Result = new OkObjectResult("my custom policy was checked");

        return Task.CompletedTask;
    }
}

public static class DynamicAuthorizationPolicies
{
    public static void RegisterMyFilters(this IServiceProvider serviceProvider)
    {
        var allEndpoints = serviceProvider
            .GetService<IActionDescriptorCollectionProvider>()
            ?.ActionDescriptors
            ?.Items;

        if (allEndpoints is null)
        {
            return;
        }

        foreach (var endpoint in allEndpoints)
        {
            // If you debug hier you will see that you can register 
            // differnt filters or attribute in different collections 
            // for the endpoint
            if (/*endpoint match some requirement*/true)
            {
                var authorizeFilter = serviceProvider.GetService<MyAuthorizationFilter>();
                var descriptor = new FilterDescriptor(authorizeFilter, FilterScope.Action);

                endpoint.FilterDescriptors.Add(descriptor);
            }
        }
    }
}

... and here is the usage:

public void ConfigureServices(IServiceCollection services)
{
    // services.Add...

    services.AddTransient<MyAuthorizationFilter>();
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    // app.Use....

    app.ApplicationServices.RegisterMyFilters();
}
  • Related