policy." name="description" /> policy." />
20655

Dependency Injection on Authorization Policy

<h3>Question</h3>

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:

<ol><li>There is a already a handler that does exactly what I need</li> <li>I need to write a new handler for each claim type and each different requirement</li> <li>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</li> </ol>

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


<h3>Answer1:</h3>

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.


<h3>Answer2:</h3>

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


<h3>Answer3:</h3>

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; } }

来源:https://stackoverflow.com/questions/59083989/dependency-injection-on-authorization-policy

Recommend

  • Sharing components between two react apps
  • Receiving a SystemFault when I query Item
  • Printing just an iFrame
  • Observable.zip is not a function
  • Building docker on yocto
  • Handle ACAccountStoreDidChangeNotification for Facebook & Twitter in iOS 6+
  • How do you change SubSonic 3's connection string on the fly?
  • Draggable/Droppable for Battleship game
  • Buildbot running sequential builders after they're finished
  • import cv2 doesn't give error on command-Prompt but error on IDLE on Windows 10, Python 3.6.4
  • Test an application behind a proxy server using Robot Framework and Selenium2Library
  • Jquery Skill bar effect starts when you scroll to the section
  • Adding items to an already existing jlist from another class
  • Advertising Identifier for devices lower than iOS 6.0
  • Velocity (VM) template request parameters: Getting GET variables
  • Laravel 5.7: Custom blade template for Maintenance Mode but not 503.blade.php
  • Gitlab: copy project to other git lab repository
  • Debugging php script timeout?
  • trigger ontouch event programmatically
  • Annotate objects in a queryset with next and previous object ids
  • Creating 2d platforms using JavaScript
  • Typeahead.js does give me suggestions but doesn't select them
  • PHPMailer return to AJAX
  • How convert html to BBcode in C#
  • How to use Streams api peek() function and make it work?
  • Another “Cannot make static reference…” Question
  • How to decleare char *const argv[] in swift [duplicate]
  • Spring Boot fails to start
  • How to get rgb from transparent pixel in js
  • WPF custom control and direct content support