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.
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.
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
public override void OnAuthorization(AuthorizationContext filterContext)
ActionDescriptor action = filterContext.ActionDescriptor;
bool IsUnsecured = action.GetCustomAttributes(
typeof(UnsecuredActionAttribute), true).Count() > 0;
filterContext.HttpContext.SkipAuthorization = IsUnsecured;
CustomAuthorizeAttribute performs the authorization check only if
protected override bool AuthorizeCore(HttpContextBase httpContext)
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.
And the unsecured controller works without any authorization required.
- 23rd August, 2010: Initial post
- 24th August, 2010: Updated article and source code