Authorizing Access via Attributes in ASP.NET MVC Without Magic Strings

Recently I developed a strategy which I think works well for authorizing access to user groups (Roles) without using the string names of those groups.

The problem I am trying to avoid is doing something like [Authorize(Roles=”AdminRole”)] on a controller or action since I know the role names can change & one typo can mess everything up.

Role Names

So first of all I usually have a static class which has the names & aliases for all roles in case they change:

public static class RoleNames
{
    public static readonly string Supervisor = "Supervisor";
    public static readonly string Admin = "StateOffice";
    public static readonly string ProjectAdmin = "ProjectAdmin";
    public static readonly string DelegateSupervisor = "Delegate";
}

 

This is pretty standard for me, but unfortunately I can’t just do [Authorize(Roles=RolesNames.Admin)] because attributes requires constant expressions.  So as a solution I came up with the idea of creating a custom attribute which will tightly control access based on specific role criteria.

Creating a Custom Authorize Attribute

When creating the custom authorize attribute I inherit from AuthorizeAttribute since it already contains most of the logic I need.  All I need to do is set the Roles property in the constructor to a comma delimited list of the authorized roles, and the authorize attribute base class will take care of the rest.

For example – to restrict access to just the admin role:  

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class AdminOnlyAttribute : AuthorizeAttribute
{
    public AdminOnlyAttribute()
    {
        Roles = RoleNames.Admin;
    }
}

Or if you want to include the project admins as well:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class AdminOnlyAttribute : AuthorizeAttribute
{
    public AdminOnlyAttribute()
    {
        var authorizedRoles = new[] {RoleNames.Admin, RoleNames.ProjectAdmin};
 
        Roles = string.Join(",", authorizedRoles);
    }
}

Usage

Then on your controller you restrict access like this

[AdminOnly]
public class AdminController : Controller{}

And it also works on an action

public class AdminController : Controller
{
    [AdminOnly]
    public ActionResult AdminOnlyAction()
    {
        return View();
    }
}

 

Enjoy!

20 Comments

  • Makes sense, especially if you want other things to change based on role (e.g. theme).

    For the simpler cases, though, why not just use const's instead of static readonly strings?

  • Even though it is a simple implementation it seems that it could get ugly pretty quick. Having to create an attribute for every combination of roles you want to authorize seems like a lot of extra work. I think a better solution would be having a role lookup based on the calling controller, action, and method.

  • Good information you shared with us. Thanks Scott. You are rocking...

  • Good Article.

  • @Eric, This is probably a stylistic decision and would definitely depend on the number of roles/role groups in your system. I feel that erring on the side of being more expressive with custom attributes for each role is very readable and manageable as long as there aren't an overabundance of them.

  • nice one.

    can we block access completely in a base controller, then whitelist who's allowed using AuthorizeAttributes? feels safer that way.

  • If your role names are constant, better make the `const` rather than `static readonly`. This will also allow you to use them as constant expressions.

  • I do much the same thing, except I use an enum with the [Flags] attribute. When a user logs in, I build the value and save it in session. Then I can just use

    [CustomAuthorize(Roles = Roles.Manager|Roles.ProjectLeader)]

    @ooswald, yes, attributes placed in a base controller, then inherited, will carry through.

    [CustomAuthorize(Roles = Roles.Admin)]
    public class AdminController : ApplicationController { }

    public class UsersController : AdminController
    {
    // this controller will also require Admin permission.
    }

  • @paul.vencill & @Troels Thomsen,
    Good suggestion re: using const instead of static readonly strings. As soon as I made the RoleNames class static I should have made this change as well, it is a lot cleaner.

    So if I use const strings I could do [Authorize(Roles=RoleNames.Admin)]. I still prefer the explicit attribute authorization method mentioned in the post, but I am always glad to have more options!

  • отличный пост, автор пиши ещё

  • I also build custom attributes for my sites. I also tend to build extension methods for toggling the visibility of links and controls on my view pages.

  • Nice work, I like the fact that defining custom attributes abstracts which roles are included. You can easily add or remove roles without touching any of the controller or page code.

    Also, taking this one step further you could register roles for each attribute in the database to make updates on the fly without touching any code.

  • Does anybody have suggestion if I have two domains where one trusts other and one doesn't trust other.

  • Although i accept each of the ideas you've presented with your post. They're really convincing and may certainly work.
    Still, the posts are too short for beginners. Could you please prolong
    them a little from subsequent time? Thanks for ones post.

  • Some really interesting points you've written.Assisted us a lot, just what I've been searching for : D.

  • Pretty a part of content. I just became conscious of your weblog plus accession capital
    to claim we get actually loved account your blog posts.
    Any way I’ll be subscribing to your augment and also I success you get admission to consistently quickly.

  • Enjoyed looking through this, very nutrients, thanks.

  • I wish to read much more reasons for having it!

  • In order to gain the unsurpassable bliss of the Self, the yogin willingly adopts a life of strict discipline.?|The aspirant begins by carefully regulating his or her moral behavior.? This forms the bedrock of all types of Yoga.|Reduced to its bare bones, yogic morality is the recognition of the universal Self in all other beings.? The various moral rules expounded in the Yoga scriptures are a symbolic bow to the Self within the other person.|Thus Yoga morality is inseparable from Yoga metaphysics.? In their moral conduct, the yogins aspire to preserve the moral order of the cosmos within the limited orbit of their personal existence.|In other words, they seek to uphold the ideals of harmony and balance.? This endeavor is by no means unique to Yoga.|Rather the moral code followed by its practitioners is universal and can be found in all the great religious traditions of the world.|As the American social critic Theodore Roszak correctly understood, the yogin’s first step must necessarily be a moral one%7

  • In order to gain the unsurpassable bliss of the Self, the yogin willingly adopts a life of strict discipline.?|The aspirant begins by carefully regulating his or her moral behavior.? This forms the bedrock of all types of Yoga.|Reduced to its bare bones, yogic morality is the recognition of the universal Self in all other beings.? The various moral rules expounded in the Yoga scriptures are a symbolic bow to the Self within the other person.|Thus Yoga morality is inseparable from Yoga metaphysics.? In their moral conduct, the yogins aspire to preserve the moral order of the cosmos within the limited orbit of their personal existence.|In other words, they seek to uphold the ideals of harmony and balance.? This endeavor is by no means unique to Yoga.|Rather the moral code followed by its practitioners is universal and can be found in all the great religious traditions of the world.|As the American social critic Theodore Roszak correctly understood, the yogin’s first step must necessarily be a moral one}

Comments have been disabled for this content.