rlesias
rlesias

Reputation: 6277

How to use the Authorize attribute both at the controller and action level?

I have implemented my own custom Authorize attribute.

The attribute is applied both at the controller level and at the action level.

Here is an example of what I need to do:

[ClaimsAuthorize(Roles = "AdvancedUsers")]
public class SecurityController : Controller
{
    [ClaimsAuthorize(Roles = "Administrators")]
    public ActionResult AdministrativeTask()
    {
        return View();
    }

    public ActionResult SomeOtherAction()
    {
        return View();
    }
}

Currently if a user has the Administrator Role but not the AdvancedUsers role, he cannot execute "Administrative Task".

How can I change this behavior to perform a security check at the action level even if the user is not authorized at the controller level?

For the moment, the only solution I can think about is to implement 2 attributes: one for securing controllers, another for securing actions. Then I would play with the Order property to execute the one at the action level first.

However, I would prefer a solution with a single attribute if possible.

Upvotes: 10

Views: 15546

Answers (5)

Csaba Toth
Csaba Toth

Reputation: 10697

Use built-in [OverrideAuthorization]:

[ClaimsAuthorize(Roles = "AdvancedUsers")]
public class SecurityController : Controller
{
    [OverrideAuthorization]
    [ClaimsAuthorize(Roles = "Administrators")]
    public ActionResult AdministrativeTask()
    {
        return View();
    }

    public ActionResult SomeOtherAction()
    {
        return View();
    }
}

OverrideAuthorization Attribute is available for MVC 5 (at least) and up. Once you decorate the Action with it, also decorate with the new Role and that will take effect over the Controller level Role.

Upvotes: 9

Chris Coulson
Chris Coulson

Reputation: 494

You need two authorization attributes - a base one with all authorization logic, and a second one, derived from the base attribute, that is only used to override the base attribute.

Example authorization attributes:

public class ClaimsAuthorizeAttribute : AuthorizeAttribute
{
    protected bool _canOverride = true;

    //...custom authorization code goes here.....

    public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext actionContext)
    {
        //Don't authorize if the override attribute exists
        if (_canOverride && actionContext.ActionDescriptor.GetCustomAttributes<OverrideClaimsAuthorizeAttribute>().Any())
        {
            return;
        }
        base.OnAuthorization(actionContext);
    }

}


public class OverrideClaimsAuthorizeAttribute : ClaimsAuthorizeAttribute
    {
        public OverrideClaimsAuthorizeAttribute ()
            : base()
        {
            _canOverride = false;
        }

    }

In the base authorization attribute we are saying to go ahead and authorize as normal, as long as the OverrideClaimsAuthorizeAttribute doesn't exist. If the OverrideClaimsAuthorizeAttribute does exist, then only run the authorization on classes where _canOverride is false (ie the OverrideClaimsAuthorizeAttribute class itself).

Example usage:

[ClaimsAuthorize(Roles = "AdvancedUsers")]
public class SecurityController : Controller
{

    //Ignores the controller authorization and authorizes with Roles=Administrators
    [OverrideClaimsAuthorize(Roles = "Administrators")]
    public ActionResult AdministrativeTask()
    {
        return View();
    }


    //Runs both the controller and action authorization, so authorizes with Roles=Administrators AND Roles=AdvancedUsers
    [ClaimsAuthorize(Roles = "Administrators")]
    public ActionResult AdvancedAdministrativeTask()
    {
        return View();
    }

    //authorizes with controller authorization: Roles=AdvancedUsers
    public ActionResult SomeOtherAction()
    {
        return View();
    }
}

Upvotes: 1

Suraj Singh
Suraj Singh

Reputation: 4059

To make specific actions restricted you simply use the Authorize-attribute on the methods that handle these actions. When you mark an action method with the Authorize attribute, access to that action method is restricted to users who are both authenticated and authorized.

     //[ClaimsAuthorize(Roles = "AdvancedUsers")]
     public class SecurityController : Controller
     {

        {
        [ClaimsAuthorize(Roles ="Administrators", "Role2","Role3")]
        public ActionResult AdministrativeTask()
        {
            return View();
        }
    }

OR you can override your authorization at controller level , Create a new OverrideAuthorizeAttribute attribute.

public class OverrideAuthorizeAttribute : AuthorizeAttribute {
    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        base.OnAuthorization(filterContext);
    }
}

and you can use this attribute to override your controller level autorization.

[ClaimsAuthorize(Roles = "AdvancedUsers")]
public class SecurityController : Controller
{
    [ClaimsAuthorize(Roles = "Administrators")]
    public ActionResult AdministrativeTask()
    {
        return View();
    }
     [OverrideAuthorizeAttribute(Roles ="xxxx")] // This role will override controller                   
                                                  //level authorization 
    public ActionResult SomeOtherAction()
    {
        return View();
    }
}

Upvotes: 2

Ventsyslav Raikov
Ventsyslav Raikov

Reputation: 7192

This should not be possible. Imagine the logic which MVC uses with the authorization filters.

  1. When the controller is determined - check if there is an authorization filter that applies to that controller and execute it.
  2. When the action is known - do the same for the action.

In all cases a fail in authorization would short-circuit the pipeline.

Upvotes: 2

A Khudairy
A Khudairy

Reputation: 1492

Check this previous question. (check @AndyBrown answer, case 2)

For a simple way you might also try adding ( [AllowAnonymous]) to override the controller [Authorize] then add a new custom filter to check for your logic for this particular action. Or you can add the code that checks for the role just inside it.

Upvotes: 0

Related Questions