How to use a variable in [Authorize (Roles = "")]

I have an intranet MVC 5 C # web application that uses over 30 Active Directory roles and permissions often change due to business culture.

To make things easy for myself, I thought I would try something like this to determine who is allowed access to the controller action or child action.

/* This function runs a LINQ query and outputs a comma delimited string of approved active directory roles. */ private static string _approvedRoles = Helpers.QueryableExtensions.GetApprovedRoles("FourCourseAudit"); // GET: FourCourseAudits [Authorize(Roles = _approvedRoles)] public ActionResult Index(string searchBy="All", string orderBy="Campus", string orderDir="Asc") { // and so on... 

Unfortunately, I get this compile-time error: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type .

Here I am trying to use other approaches with the _approvedRoles variable like public const string and public string . I put the GetApprovedRoles function in the model, in the repository (where it is now) and in the body of the controller.

I know that roles are good because if I use this: [Authorize(Roles="DOMAIN\Role1,DOMAIN\Role2")] , it works. And this is not a feasible option for me, because the roles are changing, and this is a very large MVC site. Is there any way that I can let Roles be variable?

+7
c # asp.net-mvc
source share
4 answers

The arguments must be known at compile time, but your request is executed at run time.

The easiest way to do this is to create a custom AuthorizeAttribute attribute . Inside the Authorize() method, you can perform any checks, including querying the database. You can also pass custom parameters to the constructor if you need additional flexibility when reusing an attribute. As an example:

 public class RoleAuthorizeAttribute : AuthorizeAttribute { // or inject it private DbContext _db = new DbContext(); private string _filter; public RoleAuthorizeAttribute(string filter) { _filter = filter; } /// <summary> /// Check authorization /// </summary> /// <param name="filterContext"></param> public override void OnAuthorization(AuthorizationContext filterContext) { var currentUser = HttpContext.Current.User; // do some checks, query a database, whatever string approvedRoles = Helpers.QueryableExtensions.GetApprovedRoles(_filter); if (!currentUser.IsInRole(...)) { filterContext.Result = new RedirectToRouteResult("Error", new RouteValueDictionary()); } } } 

And use:

 [RoleAuthorize("FourCourseAudit")] 
+13
source share

This is a simple version for those who want it:

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

Using:

 [AuthorizeRoles(RoleConstant1,RoleConstant2)] 
+3
source share

For compilation of your code to succeed, you must do what is indicated in the error message that you posted.

For example, you can try something like this:

 [Authorize(Roles = "Admin,User")] 

In simple words, the values ​​you pass to the attribute as parameters must be known at compile time. They cannot be evaluated at runtime.

Update

As I said in my comment below:

The only alternative is to create a custom attribute and get approved roles there. Then you can check if the current user role matches the approved roles, and your own attribute - your filter - allows or cannot use this action.

+1
source share

you can always define a new class that extends from AuthorizeAttribute and ovveride AuthorizeCore and HandleUnauthorizedRequest and create a static class with all the constant role of declaring what I'm doing in my application.

sample code in my custom class attribute inside AuthorizeCore method

  public string Groups { get; set; } // this will be my new attribute var groups = Groups.Split(',').ToList(); var context = new PrincipalContext(ContextType.Domain,"myDomain"); var userPrincipal = UserPrincipal.FindByIdentity(context,IdentityType.SamAccountName,httpContext.User.Identity.Name); foreach(var group in groups){ // will iterate the attribute and check if that user log is in that group if(userPrincipal.IsMemberOf(context, IdentityType.Name, group)){ return true; } } 
0
source share

All Articles