Beyond Role Based Authorization in ASPNET MVC

A fairly frequent requirement in applications is to check for authorization to perform an action. At the most basic level, this might just involve seeing if the user is authenticated (at all) or checking a flag to see if they are an Admin. However, more complex requirements frequently include a variety of roles, and it’s quite common for the notion of ownership to be involved as well, with some actions being allowed if you own the item being worked on, and otherwise not. I’ve written about using the notion of Privileges over Role Checks for this exact purpose in the past, as a way to ensure the logic of such decisions is properly encapsulated so that you can follow the Don’t Repeat Yourself principle. In that article, I describe how you can test privileges, but I don’t get into how to use them at the UI level, specifically in an ASP.NET MVC application.

ASP.NET MVC Authorization

You can do basic authorization in ASP.NET MVC by using attributes. Specifically, the Authorize attribute will let you mark a controller or action as requiring authorization, and you can optionally specify certain roles and/or users who are authorized to perform this action. However, this is as far as the attribute will take you, so by itself it won’t handle the case of letting users perform certain actions on things they own, but not on others’ things.

It’s also worth noting that you can apply filters like Authorize to an entire site by using GlobalFilters (in MVC 3+). For instance, in your global.asax you can add a call to RegisterGlobalFilters(GlobalFilters.Filters) in your Application_Start() and then implement this method like so:

Then if you have only a few actions that don’t require, for instance, authorization (e.g. home page, login page), you can mark these with the AllowAnonymous attribute (in MVC 4+):

Authorizing Owners

In my case, I’m globally authorizing the users as shown, but then within each action I need to verify that the user is either an administrator or they are the owner of the resource they are managing. Originally, each action had some code in it that looked like this:

The problem, of course, is that this is boilerplate code that would need to be added to every action. Not very DRY. At first I thought I might just extract this into its own method, but since it involves a return statement, that doesn’t work well and the best I could do is write a boolean method and keep the if statements in every action method.

After a bit of research, I found out that OnActionExecuting is the best way to ensure every action within a controller runs a particular bit of code, and further, how to return a particular view from this method. With this, I was able to override OnActionExecuting in my controller in question (every action of which will include the resource being worked with) like so:

What do you think of this approach? In my case, I only have one controller that needs to do this, but if I had several I could always create a common base controller and push up this code into the base class. I’m sure I could also go the custom action filter route but that seemed like overkill for what I’m looking at doing (and you can’t actually change the behavior of the action from within the filter itself, so there would need to be more moving parts). Any suggestions on how to do this better, or does this seem like a good approach?

The _currentUser class used here is one I picked up somewhere online (not sure where at this point or I would add a link) that makes it easy to avoid a dependency on HttpContext. It looks like this:

I inject it into the class using my IOC container, in this case StructureMap. I don’t need to tell StructureMap anything about CurrentUser itself, provided it knows what to do with the constructor parameters. Thus, I include one line to tell it how to get an IIdentity:

Of course, in my tests I can simply pass in a new CurrentUser() and pass in a mock IIdentity if I care about its settings within the context of a given test. These last bits are separate from the main topic of the post, but I’m including them so the code shown is clear and not missing key ingredients, which I know can be frustrating.
  • Joe Brinkman

    I think this is a good first step, but I don’t think it goes far enough.  Having code that is generic across all methods only serves a very narrow use case.  Often there is a permission matrix and each method in your class should be mapped to a specific permission type.  Most systems have at a minimum read and write permissions, sometimes it is even more granular than that.  What is really needed is an attribute which allows you to easily add permission checks to the class and to each individual method as needed.

  • Jarod Ferguson

    I have done something similar by inheriting the 
    Authorize attribute and implementing my own check similar to your OnActionExecuting code above. You can do DI on an action by writing your own action invoker. I like that approach because I can lean into the baked in auth mechanisms.

    As for the implementation I copied the WIF Claims based authorization where each resource (IResource) would have a set of KV claims against it (ClaimsPrincipal). You might take a quick look at how that works. Its a pretty clean abstraction and if implemented correctly would handle all ACL concerns, thus no need for customize the behavior for each entity.

  • Steve Smith

    Thanks, Joe.  I still like the Privilege pattern I linked to for more complex permission requirements, but in this case the app is very simple and I know the only two cases I’m concerned with that have any permissions are admin users (literally marked with a bit flag) and owners.  It sounds like Jarod Ferguson ‘s info on WIF Claims based auth might have some good stuff to cover the more complex cases, like you’re talking about, so I’m planning on checking that out.

  • Dysanovic

    Great post Steve. Authorization is an area Im working on at the moment and your findings will prove most useful. I like your style of writing and look forward to your future blog entries.

  • Oskar

    Like Jarod I chose the path of using the Authorize attribute. I also chose not to return a view but using the HTTP status code to signal to the browser that the user was not authorized to access the resource if authorization failed. This is mostly due to my view that users should not be shown links etc to resources that they are not allowed to access.

  • Steve Smith

     I agree with this, however if users can guess at a URL for a resource they shouldn’t have access to, you still need to ensure they cannot access it.  That’s the case in my example, since the resourceId is in the URL, and a user might replace one of their own with one of another user’s.

  • Sergio Tapia Gutierrez

    Hey there, I wrote a custom membership architecture for my website because I needed a way for my application to verify permissions on a per role basis.

    Check it out and let me know what you think! :=)


  • Charles Williams

    This post is very informative. Thank you author for sharing it.

  • Auctionscripts12

    very nice thought..

  • Buy Essay online

    I am very amazed i have checked out your website.

  • Jalpesh Vadgama

    Nice post!!. Security is a big concern during this days. Your findings are great and I am going to use this in my project.

  • AlanaGrant

    Permission is an area Im working on at this time and your results will confirm most useful. I like your design of composing and look ahead to your upcoming weblog records.

  • FritzHester

    Awesome post!!. Protection is a big issue during this times. Your results are excellent and I am going to use this in my venture.

  • Providencia Adamiak

    Hey! I know this is sort of off-topic however I needed to ask. Does building a well-established blog such as yours take a lot of work? I’m brand new to blogging however I do write in my diary every day. I’d like to start a blog so I can share my own experience and feelings online. Please let me know if you have any kind of ideas or tips for brand new aspiring bloggers. Appreciate it!

  • Jeppe

    Great post on an interesting and rare subject. I have hard time finding anything else about this. Do you have any updates or news on best practice for this? (PS: You formatting is really messed up on this post !)

    • ardalis

      Thanks! Sorry about the code – I thought I’d cleaned that up previously. I’ll take care of it today. Check back.