web 2.0

Using Custom Security Attributes in ASP.NET MVC

In ASP.NET MVC it is common practice to sprinkle attributes all over your controller methods to enforce security. For example if I have an administrative section of my website that I want to restrict to users in the Admin Role I could write the following snippet of code

[Authorize( Roles = "BUILTIN\\Administrators" )]
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult LoginHistory( string userID ) 
{}

This style of securing your controller methods is convenient but it can become a nightmare to maintain. Especially if you later determine that the admin functionality in your application now should be available to the members of several Active Directory groups and a couple of random users. Due to this change, your code would end up looking something like this:

[Authorize( Roles = "MYDOMAIN\\Admins,MYDOMAIN\\Developers,MYDOMAIN\\Managers", Users = "MYDOMAIN\\User1,MYDOMAIN\\User2" )]
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult LoginHistory( string userID ) 
{}

Oh boy, this is ugly! Especially if there are methods in various controllers who all require this change. So how can we avoid this problem? By creating custom attributes! To make a custom attribute,  just create a new class in Visual Studio with the following code:

using System;
using System.Web.Mvc;

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class AdminsAttribute : AuthorizeAttribute
{
    public AdminsAttribute()
    {
        this.Roles = "BUILTIN\\Administrators,MYDOMAIN\\Developers,MYDOMAIN\\Managers";
        this.Users = "MYDOMAIN\\User1,MYDOMAIN\\User2";
    }
}

This code will create a new attribute which is called [Admins]. This is much better because we have now centralized the list of users and roles assigned to our controller code. However, this is still slightly unpleasant because we have hard coded strings in our code. Therefore I would advise you to consider loading the values dynamically from a configuration file or some other location. In any case, this new attribute will significantly clean up my controller code. My new code looks like this:

[Admins]
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult LoginHistory( string userID ) 
{}

On the flipside if you are toggling the visibility of links and controls on your View pages you can also write extension methods which will help you avoid hard coding strings in your pages. For example, I commonly find myself writing this chunk of code in my view to toggle the visibility of a link:

<%= User.IsInRole( "MYDOMAIN\\Admins" ) ? Html.ActionLink( "Delete", "Delete", new { id = Model.ID } ) : String.Empty %>

Instead of writing this code with magic strings, we can create a method on the System.Security.Principal.IPrincipal interface:

using System;
using System.Security;

public static class SecurityExtensions
{
    public static bool IsAdmin( System.Security.Principal.IPrincipal user )
    {
        return user.IsInRole( "MYDOMAIN\\Admins" );
    }
}

Now the code can be written this way instead:

<%= User.IsAdmin() ? Html.ActionLink( "Delete", "Delete", new { id = Model.ID } ) : String.Empty %>

In conclusion, by using extension methods and custom attributes you can avoid using "magic strings" in your Views and Controllers. Overall, this leads to a more maintainable and flexible design.

Comments

DotNetKicks.com , on 1/20/2010 11:29:18 PM Said:

trackback

Using Custom Security Attributes in ASP.NET MVC

You've been kicked (a good thing) - Trackback from DotNetKicks.com

drakz.com , on 1/21/2010 5:15:38 AM Said:

pingback

Pingback from drakz.com

Code Capers | Using Custom Security Attributes in ASP.NET MVC | Drakz Free Online Service

uberVU - social comments , on 1/21/2010 12:22:24 PM Said:

trackback

Social comments and analytics for this post

This post was mentioned on Twitter by mikeceranski: blogged:  Using Custom Security Attributes in ASP.NET #MVC http://goo.gl/fb/e5he #aspnet

Ryan Rivest United States, on 1/22/2010 1:14:56 PM Said:

Ryan Rivest

I really like the idea of your IPrincipal extensions.  I was doing something similar by including an "IsAdmin" property on the ViewModel base class I'm using.  Your solution is more elegant because I don't use a ViewModel for each and every page, and if I need to hide links in the MasterPage, it causes problems.. thanks!

Mike United States, on 1/22/2010 1:22:04 PM Said:

Mike

I am also starting to use Extension methods for Application and SessionState. This way I can use Session.VariableName instead of Session["MagicString"]. This really helps because it allows you to find errors at compile time instead of at run time.

DotNetShoutout , on 1/24/2010 11:06:27 AM Said:

trackback

Code Capers | Using Custom Security Attributes in ASP.NET MVC

Thank you for submitting this cool story - Trackback from DotNetShoutout

Rorry United Kingdom, on 1/24/2010 7:08:16 PM Said:

Rorry

Mike, would you be so kind and explain how you use that for Sessions?
Also, Michael, would you explain or suggest how this could be used with custom authorization? I would like to avoid built-it system and use my own database and configuration that actually inspects a series of permissions from different sources. I've used Session variables so far where I'd put an object with logged-in-user info.
Thank you.

Mike Ceranski United States, on 1/24/2010 11:23:46 PM Said:

Mike Ceranski

Hi Rorry,
   Yes, if you want to use this for sessions you can add an extension method which basically wraps calls to HttpContext.Current.Session. Application variables would be done in a similar manner by using HttpContext.Current.Application.

If you want to use Custom Authorization then I would probably start out by reading this article first: msdn.microsoft.com/en-us/library/ms998317.aspx. The default templates in ASP.NET MVC will give you a good starting point and you can make a few modifications to that template to suit your needs.

I hope this helps.
- Mike

aivolkov.ru , on 2/17/2010 1:19:13 AM Said:

pingback

Pingback from aivolkov.ru

Точка Зрения - Сайт Алексея Волкова » Повторное использование правил авторизации в пользовательском интерфейсе MVC

476.animejin.com , on 5/20/2010 1:16:33 PM Said:

pingback

Pingback from 476.animejin.com

D250 Coolant Auto Parts, D250 Used Dodge Ram 3500 Classified Listings

Comments are closed