【问题标题】:Dependency Injection on Authorization Policy授权策略的依赖注入
【发布时间】:2020-03-23 19:45:52
【问题描述】:

我想为我的 ASP.NET Core 应用创建基于声明的授权:

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

问题是我有一个不平凡的方法来解决员工编号(1 到 5),我想使用 DI 服务:

public interface IEmployeeProvider {

  string[] GetAuthorizedEmployeeIds();
}

我想注入此服务并在 AddPolicy 中使用它,例如:

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

注意

我知道我可以编写自己的 AuthorizationHandler 来轻松注入 IEmployeeProvider,但我反对这种模式,因为:

  1. 已经有一个处理程序可以满足我的需要
  2. 我需要为每种索赔类型和每个不同的要求编写一个新的处理程序
  3. 这是一种反模式,因为员工 ID 确实应该是需求的一部分,而处理程序应该是处理需求的通用组件

所以我正在寻找一种在构建策略时注入服务的方法

【问题讨论】:

    标签: c# asp.net-core dependency-injection authorization


    【解决方案1】:

    您可以使用 IServiceCollection 上的 BuildServiceProvider() 方法构建服务提供者:

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

    接口和类

    public interface IEmployeeProvider
    {
        string[] GetAuthorizedEmployeeIds();
    }
    
    public class EmployeeProvider : IEmployeeProvider
    {
        public string[] GetAuthorizedEmployeeIds()
        {
            var data = new string[] { "1", "2", "3", "4", "5" };
            return data;
        }
    }
    

    【讨论】:

    • 这个方案的问题是IEmployeeProvider可能没有完全配置好或者此时没有配置所有DI服务
    【解决方案2】:

    感谢Nkosi 的提示!

    由于AddAuthorization 基本上是在后台配置AuthorizationOptions,所以我遵循相同的模式,只是我使用OptionsBuilder 来配置带有依赖项的选项

    我创建了自己的接受依赖项的 AddAuthorization 方法:

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

    现在我可以使用它来正确配置需求:

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

    如果您需要更多依赖项,您可以采用相同的技术(OptionsBuilder.Configure 最多支持 5 个依赖项)

    显然,此解决方案在升级到较新的 ASP 版本时需要额外验证,因为 AddAuhtorization 的底层实现可能会发生变化

    【讨论】:

    • 很高兴看到您能够找到解决方案。检查我提供的建议替代方案here。快乐编码。
    【解决方案3】:

    为了补充@MichaelShterenberg 提供的答案,配置委托可以使用IServiceProvider 来允许其他依赖项

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

    根据原来的例子,可以使用

    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())
            );
        });
    
        //...
    }
    

    如果需要其他依赖,可以从服务提供者那里解决。

    【讨论】:

      猜你喜欢
      • 2014-05-07
      • 1970-01-01
      • 1970-01-01
      • 2017-01-09
      • 2010-12-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多