tags:

views:

478

answers:

2

I would like to use [Authorize] for every action in my admin controller except the Login action.

[Authorize (Roles = "Administrator")]
public class AdminController : Controller
{
    // what can I place here to disable authorize?
    public ActionResult Login()
    {
        return View();
    }
}
+1  A: 

I don't think you can do this with the standard Authorize attribute, but you could derive your own attribute from AuthorizeAttribute that takes a list of actions to allow and allows access to just those actions. You can look at the source for the AuthorizeAttribute at www.codeplex.com for ideas on how to do this. If you did, it might look like:

[AdminAuthorize (Roles = "Administrator", Exempt = "Login, Logout") ]
public class AdminController : Controller
{
    public ActionResult Login()
    {
        return View();
    }

    public ActionResult Login()
    {
        return View();
    }

    ... other, restricted actions ...
}
tvanfosson
Looks like you're correct according to http://www.codeplex.com/aspnet/SourceControl/changeset/view/17272 I'm guessing the attribute gets applied at the controller level and never gives the action an attempt to evaluate it.
Todd Smith
Hmm apparently you can't link directly to the source file on codeplex.
Todd Smith
+1  A: 

You could override the OnAuthorization method of the controller

    protected override void OnAuthorization(AuthorizationContext filterContext)
    {
        if ((string)(filterContext.RouteData.Values["action"]) == "Login")
        {
            filterContext.Cancel = true;
            filterContext.Result = Login();
        }
    }

This works but it is a hack.

Full class code used for testing:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Ajax;

namespace MvcApplication2.Controllers
{
[HandleError]
[Authorize]
public class HomeController : Controller
{
    public ActionResult Index()
    {
        ViewData["Title"] = "Home Page";
        ViewData["Message"] = "Welcome to ASP.NET MVC!";

        return View();
    }


    public ActionResult About()
    {
        ViewData["Title"] = "About Page";

        return View();
    }


    protected override void OnAuthorization(AuthorizationContext filterContext)
    {
        if ((string)(filterContext.RouteData.Values["action"]) == "Index")
        {
            filterContext.Cancel = true;
            filterContext.Result = Index();
        }
    }
}
}
MrJavaGuy
Does this get called before or after the [Authorize] attribute?
Todd Smith
It looks like the [Authoirze] attribute is evaluated first and never gets to the OnAuthoirization method.
Todd Smith
Gets called every time for me.
MrJavaGuy
Looking again at your question, you should be able to use the line fliterContext.Result = View("Login"); as well
MrJavaGuy
OnAuthorization is getting called except when I have a [Authorize] attribute on the controller itself.
Todd Smith
Are you using the beta of the MVC or one of the previews? I have the [Authorize] attribute on the controller as well.
MrJavaGuy
I'm using the beta. Perhaps the difference is the roles [Authorize (Roles = "Administrator")]
Todd Smith
nvm, I tested it again and your way appears to be working.
Todd Smith
glad to know I am not crazy :)
MrJavaGuy
There is one catch with this approach, if you have two versions of your login, one for get and one for post and your methods are decorated with [AcceptVerbs(HttpVerbs.Get)] and [AcceptVerbs(HttpVerbs.Post)] then the OnAuthorization method gets a bit more complicated.
Todd Smith
only a little, use filterContext.HttpContext.Request.HttpMethod for the verb
MrJavaGuy