I want to create a claim based authorization for my ASP.NET Core app:
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthorizat
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.
Thanks to Nkosi for the tip!
Since AddAuthorization is basically configuring AuthorizationOptions
behind the scenes, I followed the same pattern only I used OptionsBuilder
to configure options with dependencies
I created my own AddAuthorization method that accepts dependencies:
public static IServiceCollection AddAuthorization<TDep>(
this IServiceCollection services,
Action<AuthorizationOptions, TDep> configure) where TDep : class
{
services.AddOptions<AuthorizationOptions>().Configure<TDep>(configure);
return services.AddAuthorization();
}
And now I can use it to properly configure the requirement:
services.AddAuthorization<IEmployeeProvider>((options, employeeProvider> =>
{
options.AddPolicy("Founders", policy =>
policy.RequireClaim("EmployeeNumber", employeeProvider.GetAuthorizedEmployeeIds())
);
});
You can follow the same technique if you need more dependencies (OptionsBuilder.Configure
supports up to 5 dependencies)
Obviously, this solution requires extra validation when upgrading to newer ASP versions, as the underlying implementation of AddAuhtorization
may change
You can build a service provider using the BuildServiceProvider() method on the IServiceCollection:
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IEmployeeProvider, EmployeeProvider>();
var sp = services.BuildServiceProvider();
var employeeProvider = sp.GetService<IEmployeeProvider>();
string[] values = employeeProvider.GetAuthorizedEmployeeIds();
services.AddAuthorization(options =>
{
options.AddPolicy("Founders", policy =>
policy.RequireClaim("EmployeeNumber", employeeProvider.GetAuthorizedEmployeeIds()));
});
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}
interface and Class
public interface IEmployeeProvider
{
string[] GetAuthorizedEmployeeIds();
}
public class EmployeeProvider : IEmployeeProvider
{
public string[] GetAuthorizedEmployeeIds()
{
var data = new string[] { "1", "2", "3", "4", "5" };
return data;
}
}