Authorize Attribute with Multiple Roles
Solution 1
Try to create custom authorize attribute like this.
public class AuthorizeRolesAttribute : AuthorizeAttribute
{
public AuthorizeRolesAttribute(params string[] roles) : base()
{
Roles = string.Join(",", roles);
}
}
Assuming your roles will be the same for multiple controllers, create a helper class:
public static class Role
{
public const string Administrator = "Administrator";
public const string Assistant = "Assistant";
}
Then use it like so:
public class MyController : Controller
{
[AuthorizeRoles(Role.Administrator, Role.Assistant)]
public ActionResult AdminOrAssistant()
{
return View();
}
}
Solution 2
The best and simplest way I found to resolve this problem is just to concatenate roles in the Authorize attribute.
[Authorize(Roles = CustomRoles.Admin + "," + CustomRoles.OtherRole)]
with CustomRole a class with constant strings like this :
public static class CustomRoles
{
public const string Admin = "Admin";
// and so on..
}
Solution 3
Make sure you are deriving your custom attribute class off System.Web.Mvc.AuthorizeAttribute
and NOT System.Web.Http.AuthorizeAttribute
.
I ran into the same problem. Once I changed it, everything worked.
You may also want to add the following to your custom attribute class:
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true, AllowMultiple = true)]
Solution 4
What i did is the answer in @Tieson
I tweak a little in his answer. Instead of string.Join why not convert it to list?
Here is my answer:
public class AuthorizeRolesAttribute : AuthorizeAttribute
{
private new List<string> Roles;
public AuthorizeRolesAttribute(params string[] roles) : base()
{
Roles = roles.toList()
}
}
And then check the if the role is valid overriding OnAuthorization
public override void OnAuthorization(HttpActionContext actionContext)
{
if (Roles == null)
HandleUnauthorizedRequest(actionContext);
else
{
ClaimsIdentity claimsIdentity = HttpContext.Current.User.Identity as ClaimsIdentity;
string _role = claimsIdentity.FindFirst(ClaimTypes.Role).Value;
bool isAuthorize = Roles.Any(role => role == _role);
if(!isAuthorize)
HandleUnauthorizedRequest(actionContext);
}
}
And there you have it, it is now validating if the role is authorized to access the resource
Solution 5
I feel like a custom authorize attribute is overkill for this issue unless you have a large amount of roles.
Since the string must be known at compile time, why not make a static Role class that contains public strings of the roles you have defined, and then add comma separated strings with certain roles that you want to authorize:
public static class Roles
{
public const string ADMIN = "Admin";
public const string VIEWER = "Viewer";
public const string ADMIN_OR_VIEWER = ADMIN + "," + VIEWER;
}
And then you can use the Authorize Attribute like so on the Controller Class or the Controller Method (or both):
[Authorize(Roles = Roles.ADMIN]
public class ExampleController : Controller
{
[Authorize(Roles = Roles.ADMIN_OR_VIEWER)
public ActionResult Create()
{
..code here...
}
}
Related videos on Youtube
Comments
-
Christian Sauer about 3 years
I would like to add Authorization to a controller, for multiple Roles at once.
Normally that would look like this:
[Authorize(Roles = "RoleA,RoleB,RoleC")] public async Task<ActionResult> Index() { }
But I have stored my Roles in consts, since they might change or be extended at some point.
public const RoleA = "RoleA"; public const RoleB = "RoleB"; public const RoleC = "RoleC";
I cannot do this, since the string must be known at compile time:
[Authorize(Roles = string.join(",",RoleA,RoleB,RoleC)] public async Task<ActionResult> Index() { }
Is there a way to circumvent the problem?
I COULD write a const which simply contains "RoleA,RoleB,RoleC" - but I dislike magic strings and this is a magic string. Changing the name of a Role and forgetting to change the combined string would be a disaster.
I am using MVC5. ASP.NET Identity and the Role are known at compile time.
-
Mukesh Modhvadiya almost 10 yearsare you using public const string RoleA = "RoleA"; or as you have written in question?
-
Ryan Kohn over 9 yearspossible duplicate of allow multiple roles to access controller action
-
-
Christian Sauer almost 10 yearsNow that's an idea worthy of Mac Gyver ;)
-
sshine over 8 yearsI also like this solution a lot, especially because I can let my Role be an enum rather than a string. What would a good namespace and location in the project hierarchy be for placing this custom authorize attribute?
-
MacGyver over 8 years@SimonShine - I believe that, you should place it in web project e.g. in Attributes folder. However if you have multiple projects in one solution you'll need to move this to another library visible for every project.
-
sshine over 8 years@MacGyver: An Attributes folder seems like the logical choice, although I don't know if I'll be adding enough attributes to justify creating a top-level directory yet. What to name such directory is also discussed in stackoverflow.com/questions/7163698/…
-
MacGyver over 8 years@SimonShine Hey, nothing is stopping you to place this class wherever you want. Unless it's not used in views - there is always a refactoring.
-
Urielzen about 8 yearsI am not sure what is going on here, but this did NOT help me, any user regardless of the role was able to access the method.
-
Chef_Code about 8 yearsVery Nice SIR, Works like a charm
-
GhostCat about 7 yearsValueable; but this should be a comment; not an answer.
-
John Leidegren over 6 yearsThis example doesn't work, or at least not the way you might think. For example, while novel the
ADMIN_OR_VIEWER
role on the action is redundant because you will not be allowed to get to theCreate
method if you don't already have theADMIN
role. In this caseVIEWER
will never be able to invokeCreate
method. -
EduLopez over 6 yearsThis solution is not scalable too. There will be a point where you have too many roles with different actions and you shouldnt create every combination
-
fraser jordan about 6 yearsI just tried this and found referencing the library
System.Web.Http.AuthorizeAttribute
INSTEAD OFSystem.Web.Mvc.AuthorizeAttribute
-
Eric Eskildsen over 5 yearsBoth your answer and the accepted answer will trigger authorization if implemented correctly (I'm using the accepted in a production web app). Proposing an edit to remove the comments about the accepted answer.
-
RJB over 4 yearsSame issue as @Urielzen, but it was fixed by the answer below from Jerry Finegan (using "System.Web.Mvc.AuthorizeAttribute and NOT System.Web.Http.AuthorizeAttribute")
-
Varun over 3 yearsIf the Roles were Enums then you can use something like, [Authorize(Roles = nameof(UserRoleEnum.User) + "," + nameof(UserRoleEnum.Admin))]
-
Tom Lint almost 3 years@JohnLeidegren this is incorrect. The action-level AuthorizeAttribute overrides the controller-level AuthorizeAttribute, otherwise, you would not be able to have actions decorated with AllowAnonymousAttribute in a controller with an AuthorizeAttribute