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

I applied my own 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 an administrator role but not the AdvancedUsers role, he cannot complete the "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?

At the moment, the only solution I can think of is to implement 2 attributes: one to protect the controllers, the other to provide security. Then I will play with the Order property to complete the first at the action level.

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

+6
source share
5 answers

To limit certain actions, you simply use the Authorize attribute for methods that process these actions. When you mark an action method with the Authorize attribute, access to this action method is limited to users who are authenticated and authorized.

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

OR you can redefine your authorization at the 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 authorization at the controller level.

 [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(); } } 
+3
source

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

  • When the controller is defined - check if there is an authorization filter that applies to this controller and execute it.
  • When the action is known, do the same for the action.

In all cases, denial of authorization will result in a short circuit of the conveyor.

+2
source

You need two authorization attributes - the basic one with all the authorization logic and the second one obtained from the basic attribute, which is used only to redefine the basic 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 basic authorization attribute, we say that we go ahead and log in as usual until the OverrideClaimsAuthorizeAttribute attribute exists. If the OverrideClaimsAuthorizeAttribute attribute exists, then authorize only in classes where _canOverride is false (i.e., the OverrideClaimsAuthorizeAttribute class itself).

Usage example:

 [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(); } } 
+1
source

Use the built-in [OverrideAuthorization()] :

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

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

For an easy way, you can also try adding ([AllowAnonymous]) to override the controller [Log In] then add a new custom filter to check your logic for this particular action. Or you can add code that only checks the role inside it.

0
source

Source: https://habr.com/ru/post/956086/


All Articles