Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dependency Injection on Authorization Policy

I want to create a claim based authorization for my ASP.NET Core app:

public void ConfigureServices(IServiceCollection services)
{
    services.AddAuthorization(options =>
    {
        options.AddPolicy("Founders", policy =>
                          policy.RequireClaim("EmployeeNumber", "1", "2", "3", "4", "5"));
    });
}

The problem is that I have a non trivial method to resolve the employee numbers (1 to 5) and I want to use a DI service:

public interface IEmployeeProvider {

  string[] GetAuthorizedEmployeeIds();
}

I would like to inject this service and use it in AddPolicy, something like:

services.AddAuthorization(options =>
{
    options.AddPolicy("Founders", policy =>
              policy.RequireClaim("EmployeeNumber", *employeeProvider.GetAuthorizedEmployeeIds()));
});

Note

I know that I can write my own AuthorizationHandler where I can easily inject IEmployeeProvider but I'm against this pattern because:

  1. There is a already a handler that does exactly what I need
  2. I need to write a new handler for each claim type and each different requirement
  3. This is an anti pattern because the employee ids should really be part of the requirement while the handler should be generic component that handles the requirements

So I'm looking for a way to inject services when the policy is being built

like image 216
Michael Shterenberg Avatar asked Dec 31 '22 11:12

Michael Shterenberg


1 Answers

To supplement the provided answer by @MichaelShterenberg, the configuration delegate can use a IServiceProvider to allow for additional dependencies

public static IServiceCollection AddAuthorization(this IServiceCollection services,
    Action<AuthorizationOptions, IServiceProvider> configure) {
    services.AddOptions<AuthorizationOptions>().Configure<IServiceProvider>(configure);
    return services.AddAuthorization();
}

Which, based on the original example, can be used

public void ConfigureServices(IServiceCollection services) {

    //...

    service.AddScoped<IEmployeeProvider, EmployeeProvider>();

    services.AddAuthorization((options, sp) => {
        IEmployeeProvider employeeProvider = sp.GetRequiredService<IEmployeeProvider>();
        options.AddPolicy("Founders", policy =>
            policy.RequireClaim("EmployeeNumber", employeeProvider.GetAuthorizedEmployeeIds())
        );
    });

    //...
}

If there were other dependencies needed, they could be resolved from the service provider.

like image 118
Nkosi Avatar answered Jan 08 '23 21:01

Nkosi