How to skip Authorization on a particular action method?

1.9k Views Asked by At

The code below checks Authorization on all action methods in the controller. I am using Asp.NET Core 2.2

Authorize Attribute

public class AuthorizeRolesAttribute : AuthorizeAttribute
{
    public AuthorizeRolesAttribute(params string[] roles) : base()
    {
        Roles = string.Join(",", roles);
    }
}

Controller

[AuthorizeRoles(Roles.Worker,Roles.Contractor)]
public class MyController:Controller
{
    [HttpGet]
    public ActionResult Index()
    {
       return View();
    }

    [HttpPost]
    public ActionResult Action1()
    {
       return View();
    }

    [HttpPost]
    public ActionResult Action2()
    {
       return View();
    }

}

I want to skip authorization on Index action method when I apply a particular attribute. Same way how [AllowAnonymous] attribute works. However I think [AllowAnonymous] will allow un-authenticated user. I don't want un-authenticated user to access Index. I am also trying to avoid applying Authorize attribute on individual action methods.

So controller would be

[AuthorizeRoles(Roles.Worker,Roles.Contractor)]
public class MyController:Controller
{
    [IgnoreAthorization]
    [HttpGet]
    public ActionResult Index()
    {
       return View();
    }

    [HttpPost]
    public ActionResult Action1()
    {
       return View();
    }

    [HttpPost]
    public ActionResult Action2()
    {
       return View();
    }

}

Update 1
Is there a way in policy builder to skip role based on authorization when action is decorated with a [IgnoreAuthorization] attribute. Here is my current policy in startup.cs. I am using OpenID Connect for authentication

var authorizationPolicy = new AuthorizationPolicyBuilder()
           .RequireClaim(ClaimTypes.Email)
           .RequireClaim(ClaimTypes.NameIdentifier)
           .RequireClaim(ClaimTypes.Name)
           .RequireClaim(IdentityClaimTypes.IdToken)               
           .RequireAuthenticatedUser()
           .Build();           

        // mvc
        services.AddMvc(options =>
        {
            options.Filters.Add(new AuthorizeFilter(authorizationPolicy));
        })

Update 2
Tried adding custom AuthorizeFilter but didn't work

public class MyAuthorizeFilter : AuthorizeFilter
{
    public MyAuthorizeFilter(AuthorizationPolicy policy)
        : base(policy)
    {
    }

    public override Task OnAuthorizationAsync(AuthorizationFilterContext context)
    {
        var skip = context.ActionDescriptor.EndpointMetadata.Any(x => x is IgnoreAthorization) &&
            context.HttpContext.User.Identity.IsAuthenticated;

        if (skip)
        {
            return Task.CompletedTask;
        }

        return base.OnAuthorizationAsync(context);
    }
}

and then in startup.cs add MyAuthorizeFilter

   // mvc
    services.AddMvc(options =>
    {
        options.Filters.Add(new MyAuthorizeFilter(authorizationPolicy));
    })
1

There are 1 best solutions below

0
On

To the Multiple Policy Evaluation, if you apply multiple policies to a controller or action, then all policies must pass before access is granted.

In your scenario, you want the authenticated user to access the Index page and the Roles based users to access other actions. If you set the policy to the controller, then use another policy on the action method, it will check the Controller's policy first, then, check the Action's policy.

So, based on your scenario, the only way is to set at least two policies, one for the Authenticated User one for the Role based users. Then, apply the policies as below:

public class MyController:Controller
{ 
     [Authorize(policy: "EveryOne")]
     public ... Index(){
     }
    [HttpPost]
    [Authorize(policy: "Role")]
    public ActionResult Action1()
    {
       return View();
    }

    [HttpPost]
    [Authorize(policy: "Role")]
    public ActionResult Action2()
    {
       return View();
    }
 }

More detail information, refer the following articles:

Multiple Policy Evaluation

Authorize Attribute should have a flag to Override previous Authorize Attributes Controller - Method