对授权策略的依赖注入

问题描述 投票:1回答:3

我想为我的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
3个回答
1
投票

感谢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的基础实现可能会更改


0
投票

为了用@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())
        );
    });

    //...
}

如果需要其他依赖项,则可以从服务提供商处解决。


-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;
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.