How to add multiple policies in action using Authorize attribute using identity 2.0?

If you simply want to apply multiple policies, you can do this:

[Authorize(Policy = "Asset")]
[Authorize(Policy = "Edit")]
public class MyController : Controller {

}

EDIT: to clarify, this is additive - you must pass both policy requirements.


For multiple policys, you could implement your own AuthorizeAttribute.

  • MultiplePolicysAuthorizeAttribute

    public class MultiplePolicysAuthorizeAttribute : TypeFilterAttribute
    {
         public MultiplePolicysAuthorizeAttribute(string policys, bool isAnd = false) : base(typeof(MultiplePolicysAuthorizeFilter))
         {
             Arguments = new object[] { policys, isAnd };
         }
    }
    
  • MultiplePolicysAuthorizeFilter

    public class MultiplePolicysAuthorizeFilter : IAsyncAuthorizationFilter
    {
        private readonly IAuthorizationService _authorization;
        public string Policys { get; private set; }
        public bool IsAnd { get; private set; }
    
        public MultiplePolicysAuthorizeFilter(string policys, bool isAnd, IAuthorizationService authorization)
        {
           Policys = policys;
           IsAnd = isAnd;
           _authorization = authorization;
        }
    
        public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
        {
            var policys = Policys.Split(";").ToList();
            if (IsAnd)
            {
                foreach (var policy in policys)
                {
                    var authorized = await _authorization.AuthorizeAsync(context.HttpContext.User, policy);
                    if (!authorized.Succeeded)
                    {
                        context.Result = new ForbidResult();
                        return;
                    }
    
                }
             }
             else
             {
                foreach (var policy in policys)
                {
                     var authorized = await _authorization.AuthorizeAsync(context.HttpContext.User, policy);
                     if (authorized.Succeeded)
                     {
                         return;
                     }
    
                }
                context.Result = new ForbidResult();
                return;
            }
         }
    }
    
  • only require one of the policy

    [MultiplePolicysAuthorize("Assets View;Assets Edit;Assets Delete")]
    
  • only require all the policys

    [MultiplePolicysAuthorize("Assets View;Assets Edit;Assets Delete", true)]
    

You can use make multiple requirements class implementing IAuthorizationRequirement, and register to the DI container the multiple requirements handlers of AuthorizationHandler.

So you can simply add them to your Policy using the AddRequirement inside AuthorizationPolicyBuilder

public AuthorizationPolicyBuilder AddRequirements(params IAuthorizationRequirement[] requirements);

Startup.cs:

services.AddScoped<IAuthorizationHandler, FooHandler>();
services.AddScoped<IAuthorizationHandler, BooHandler>();

services.AddAuthorization(authorizationOptions =>
{
    authorizationOptions.AddPolicy(
        "FooAndBooPolicy",
        policyBuilder =>
        {
            policyBuilder.RequireAuthenticatedUser();
            policyBuilder.AddRequirements(new FooRequirement(), new BooRequirement());
        });
});

Requirements.cs:

public class FooRequirement : IAuthorizationRequirement { }    
public class FooHandler : AuthorizationHandler<FooRequirement>
{
    protected override Task HandleRequirementAsync(AuthorizationContext context, FooRequirement requirement)
    {
        if (context.User.HasClaim(c => c.Type == "Foo" && c.Value == true))
        {
            context.Succeed(requirement);
            return Task.FromResult(0);
        }
    }
}

public class BooRequirement : IAuthorizationRequirement { }    
public class BooHandler : AuthorizationHandler<BooRequirement>
{
    protected override Task HandleRequirementAsync(AuthorizationContext context, BooRequirement requirement)
    {
        if (context.User.HasClaim(c => c.Type == "Boo" && c.Value == true))
        {
            context.Succeed(requirement);
            return Task.FromResult(0);
        }
    }
}