Sunday, March 20, 2011

Simplify Authorization with an Attribute




There are about 10 bajillion ways to figure out if a user is authorized to call a method or see a page or whatever else. This particular post is about how to create an attribute to see if a user is authorized to do a particular action. I’ll give an example using MVC and WebForms.

For MVC, you’d create a filter attribute and override the OnActionExecuting method like this:

    [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public class AllowAttribute : ActionFilterAttribute
{
private readonly string[] _allowedRoles;

public AllowAttribute(params string[] allowedRoles)
{
_allowedRoles = allowedRoles;
}

public override void OnActionExecuting(ActionExecutingContext filterContext)
{
//if (authorized)
//return

filterContext.Controller.ViewData.ModelState.AddModelError("AccessDenied", "Access denied");
throw new AccessDeniedException();
}
}

The commented out part is where you’d actually call your authorization service or however you want to go about authorizing a user. I’m accepting the roles allowed for the particular method in the constructor. Here’s the AccessDeniedException:

    public class AccessDeniedException : BaseHttpException
{
public AccessDeniedException() : base((int)HttpStatusCode.Unauthorized, "User not authorized.") { }
}

public class BaseHttpException : HttpException
{
public BaseHttpException(int httpCode, string message) : base(httpCode, message) { }
}

So on the controller action, it’d look something like this:

        [Allow(Roles.Administrator, Roles.OtherSampleRole)]
public ActionResult SampleAction()
{
return RedirectToAction("SampleAction");
}

Since I hate risking mistyping something, I’ll typically setup an enum or a class with consts…something like this:

    public class Roles
{
public const string Administrator = "Administrator";
public const string OtherSampleRole = "OtherSampleRole";
}

Here’s the WebForm version:

    [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class AllowAttribute : Attribute
{
public AllowAttribute(params string[] allowedRoles)
{
//if (authorized)
//return

throw new AccessDeniedException();
}
}

This one is used like this:

    [Allow(Roles.Administrator, Roles.OtherSampleRole)]
public class SamplePage : System.Web.UI.Page
{
/*...*/
}

The WebForm version is based on page instead of by action like on the MVC sample. Pretty simple stuff…hope this helps.

Also, you'll need to add the 401 code to the custom errors section and redirect to an access denied page.

Thanks for reading!

Shout it

kick it on DotNetKicks.com

Related Posts Plugin for WordPress, Blogger...