在asp.net核心中使用依赖注入的授权策略

时间:2017-10-02 14:36:05

标签: dependency-injection .net-core

我想为aspnet.core创建基于策略的授权

我有很多我想要实现的策略,我不想使用策略来扩展startup.cs文件。

public void ConfigureServices(IServiceCollection services)
{
    services.AddAuthorization(options =>
    {
        options
            .AddPolicy("Policy1", policyBuilder =>
            {
                policyBuilder
                    .RequireClaim("scope", "1")
                    .Build();
            }).AddPolicy("Policy2", policyBuilder =>
            {
                policyBuilder
                    .RequireClaim("scope", "2")
                    .Build();
            }).AddPolicy("Policy3", policyBuilder =>
            {
                policyBuilder
                    .RequireClaim("scope", "3")
                    .Build();
            }).AddPolicy("Policy4", policyBuilder =>
            {
                policyBuilder
                    .RequireClaim("scope", "4")
                    .Build();
                ;
            });
    });
}

我想在启动时注入所有策略。

有没有人知道如何做到这一点?

我考虑创建一个通过反射获取所有策略的工厂,但我真的希望能够将类注入到策略中。

e.g。

public interface IPolicy
{
    string Name { get; }
    AuthorizationPolicy AuthorizationPolicy { get; }
}

public class UserCreatePolicy : IPolicy
{
    public const string Name = "UserCreatePolicy";

    public UserCreatePolicy(IUserRoleService userRoleService)
    {
        _userRoleService = userRoleService;
    }

    public AuthorizationPolicy AuthorizationPolicy =>
        new AuthorizationPolicyBuilder()
            .RequireClaim("scope", _userRoleService.GetRole(1))
            .Build();
}

public class AuthorizationPolicyFactory
{
    public static void Create(AuthorizationOptions authorizationOptions)
    {
        typeof(IPolicy).Assembly
            .GetTypes()
            .Where(x => typeof(IPolicy).IsAssignableFrom(x) && !x.IsAbstract && !x.IsInterface)
            .ToList()
            .ForEach(type =>
            {
                if (Activator.CreateInstance(type) is IPolicy policy)
                {
                    authorizationOptions.AddPolicy(policy.Name, policy.AuthorizationPolicy);
                }
            });
    }
}

理想情况下,我不想使用反射,而是使用依赖注入。

1 个答案:

答案 0 :(得分:1)

您可以直接使用IServiceProvider。即使它是这种情况的反模式,我也没有办法解决。

public interface IPolicy
{
    string Name { get; }
    void ConfigurePolicy(AuthorizationPolicyBuilder builder);
}

public class UserCreatePolicy : IPolicy
{
    public string Name { get; } = "UserCreatePolicy";

    public UserCreatePolicy(IUserRoleService userRoleService)
    {
        _userRoleService = userRoleService;
    }

    public void ConfigurePolicy(AuthorizationPolicyBuilder builder)
    {
        builder
            .RequireClaim("scope", _userRoleService.GetRole(1))
            .Build();
    }
}

要配置此策略,我已经创建了一个扩展方法。

public static class AuthorizationPolicyExtensions
{
    public static void ConfigureAuthorizationPolicies(this IServiceCollection serviceCollection, AuthorizationOptions authorizationOptions)
    {
        var policiesTypes = typeof(IPolicy).Assembly
            .GetTypes()
            .Where(x => typeof(IPolicy).IsAssignableFrom(x) && !x.IsAbstract && !x.IsInterface)
            .ToList();

        foreach (var type in policiesTypes)
        {
            serviceCollection.AddTransient(type);
        }

        var serviceProvider = serviceCollection.BuildServiceProvider();

        var policies = policiesTypes
            .Select(x => serviceProvider.GetService(x) as IPolicy)
            .Where(x => x != null);

        foreach (var policy in policies)
        {
            authorizationOptions.AddPolicy(policy.Name, policy.ConfigurePolicy);
        }
    }
}

它搜索IPolicy类型并将它们注册到控件容器的反转中。然后,它将使用IPolicy解析那些IServiceProvider并注册它们。