0

I want to create policy based authorisation for aspnet.core

I have lots of policies that I want to implement and I don't want to bloat the startup.cs file with policies.

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

I want to inject all the policies at startup.

Does anyone have any idea how to do this?

I thought about creating a factory that gets all the policies by reflection, but I really want to be able to inject classes into the policies.

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

Ideally I don't want to have to use reflection and instead use Dependency injection.

1 Answer 1

1

You could use the IServiceProvider directly. Even if it is an anti pattern for such cases I see no way around.

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

To configure this policies I've created an extension method.

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

It searches for IPolicy types and registers them in the inversion of control container. Then it will resolve those IPolicy's with the IServiceProvider and register them.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.