Live Demos

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

2 comments:

  1. Hello! I know this is kinda off topic but I'd figured I'd ask.

    Would you be interested in exchanging links or maybe guest writing a blog article or vice-versa?
    My blog goes over a lot of the same subjects as yours and I feel we could greatly benefit
    from each other. If you might be interested
    feel free to shoot me an email. I look forward to hearing from you!
    Excellent blog by the way!
    My weblog ; forja

    ReplyDelete
  2. Having read this I thought it was rather enlightening.

    I appreciate you spending some time and effort
    to put this informative article together. I once again find myself personally spending a lot of time both reading and
    leaving comments. But so what, it was still
    worth it!
    Stop by my site - bacalao

    ReplyDelete