Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / ASP.NET

ASP.NET MVC - AuthorizeWithExemptionsAttribute

4.57/5 (5 votes)
26 Aug 2010CPOL2 min read 34K   475  
This base controller will secure all your actions except those which will be marked as UnsecuredAction.

Introduction

In this article, I'll provide you with a solution for securing ASP.NET MVC application's controllers in a way that all the actions are secured except those you define as unsecure (by default, all the actions are unsecure unless you define them as secure).

I encountered a problem in the ASP.NET MVC authorization model, which is built as opt-in. You can secure an action or a controller using the [Authorize] attribute. The problem is that if you want to secure a whole controller and make some actions in that controller as not secured - you can't.

This article will explain to you how you can secure a whole controller and make some actions as not secured within it.

This project was written in Visual Studio 2010 as an ASP.NET MVC 2 project.

Background

I was looking for a solution to that problem, and couldn't find a reasonable one. Other solutions suggested to:

  • Move the unsecured actions to another controller (not secured)
  • Write the AuthorizeCore method to be dependent on the Action's names
  • Put the [Authorize] attribute on all the actions except the non-secured actions

In this article, I'll provide you with my solution to this problem.

Using the Code

To use the code, you'll need your controllers to put any [CustomAuthorize] attribute which inherits from AuthorizeWithExemptionsAttribute on your controllers. Calling any action on this controller will include an authorization check. If you want to mark an Action as non-secured, just put the [UnsecuredAction] Attribute above it.

Explanation

The core of this solution is in the [AuthorizeWithExemptions] Attribute in the OnAuthorization method. This method checks if the called Action has the UnsecuredActionAttribute, and if it does, it marks filterContext.HttpContext.SkipAuthorization as true.

C#
public override void OnAuthorization(AuthorizationContext filterContext)
{
    ActionDescriptor action = filterContext.ActionDescriptor;
    bool IsUnsecured = action.GetCustomAttributes(
                         typeof(UnsecuredActionAttribute), true).Count() > 0;

    //If doesn't have UnsecuredActionAttribute - then do the authorization
    filterContext.HttpContext.SkipAuthorization = IsUnsecured;

    base.OnAuthorization(filterContext);
}

Then, CustomAuthorizeAttribute performs the authorization check only if SkipAuthorization is false.

C#
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
  if (httpContext.SkipAuthorization)
  {
      return true;
  }

  // Do any authorization logic here
  return httpContext.Request.QueryString["password"] == "password";
}

* Of course, never provide the password in the QueryString, it was made like that just for the ease of the example.

So now, when you try to invoke the secured controller, you get the HTTP error code 401: Unauthorized.

Image 1

And the unsecured controller works without any authorization required.

Image 2

History

  • 23rd August, 2010: Initial post
  • 24th August, 2010: Updated article and source code

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)