简体   繁体   中英

ASP.NET MVC: Problem setting the Authorize attribute Role from a variable, requires const

I am having a problem setting the Authorize attribute Role value from a variable. The error message says it requires a const variable. When I create a const type variable it works fine but I am trying to load the value from the Web.Config file or anything else that will allow the end user to set this. I'm using integrated Windows authentication since this is an intranet only application.

Is there a way to check the users role from a controller? I will use this in an if statement to authenticate instead of an attribute.

[Authorize(Roles = Config.GMPUser)]
public ActionResult Index()
   {
      return View();
   }

I have a class called StringResources that provides access to static string values. I ran into the same snag and solved the problem in the following manner. I inherited from the AuthorizeAttribute class and added a method override for the AuthorizeCore method. The functionality of the method had a call to IsInRole() and passes in the static string property. That did the trick. The only problem is having to create separate classes for each role (or for combinations of roles in whatever manner your business logic dictates).

public class SystemAdministratorAuthorizationRequiredAttribute
        : AuthorizeAttribute
    {
        protected override bool AuthorizeCore(System.Security.Principal.IPrincipal user)
        {
            return
                user.IsInRole(
                StringResources.AdministrationViewsStrings.SystemAdministratorRoleName
                );
        }
    }

Attributes are burned at compile time, so as indicated, you can only use them with constants. You also can't change attributes, since even if it seems to let you, it doesn't "stick" next time you fetch the value back out. tvanfosson's User.InRole( "RoleName" ) is probably the best option (he has my +1).

Just to illustrate the issue with updating attributes:

class FooAttribute : Attribute
{
    public string Bar { get; set; }
}
static class Program
{
    [Foo(Bar="abc")]
    public static void Main()
    {
        MethodInfo method = typeof(Program).GetMethod("Main");
        var attrib = (FooAttribute) Attribute.GetCustomAttribute(method, typeof(FooAttribute));
        Console.WriteLine("Original: " + attrib.Bar);
        attrib.Bar = "def";
        Console.WriteLine("Updated: " + attrib.Bar);
        attrib = (FooAttribute)Attribute.GetCustomAttribute(method, typeof(FooAttribute));
        Console.WriteLine("Look again: " + attrib.Bar);
    }
}

Prints:

Original: abc
Updated: def
Look again: abc

Create a custom attribute like so (slightly modified version provided by david hayden's blog ):

public class MyCustomAuthorizeAttribute : AuthorizeAttribute
{
    public IAuthorizationService _authorizationService = new MyAuthorizationService();

    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
       return _authorizationService.Authorize(httpContext);
    }
}

and apply like so:

[MyCustomAuthorize]
public ActionResult Create()
{
    return View();
}

now you can put all your custom authorization logic inside your own MyAuthorizationService class. Note: in davids solution you can set the internal MyAuthorizationService with the provided accessor. Not sure if you will be able pass in a new MyAuthorizationService() to it. Haven't tried that.

You can use User.InRole( "RoleName" ) within a controller.

EDIT: The code below will not work since GetCustomAttributes() apparently returns a copy of each attribute instead of a reference to the actual attribute. Left as answer to provide context for other answers.

As far as setting it in the authorize attribute, the only idea that I have is to set it to the empty string in the attribute definition, then use reflection on the controller's type to get and modify the CustomAttribute property corresponding to the AuthorizeAttribute (ie, the one whose type is AuthorizeAttribute) for each method you care about. You should be able to set the Roles property to your configuration item that way.

var attributes = typeof(MyController).GetMethod("Index")
                                     .GetCustomAttributes(typeof(AuthorizeAttribute),
                                                          false)
                 as AuthorizeAttribute;

attributes[0].Roles = Config.GMPUser;

I suppose that you would do this in your Global.asax file on application start so that it only needs to be done once.

You could create a new Authorize class like so:

[AttributeUsage(AttributeTargets.All, Inherited = true, AllowMultiple = true)]
public class AuthorizedGmp : AuthorizeAttribute
{
    public AuthorizedGmp()
    {
        Roles = Config.GMPUser;
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM