views:

2237

answers:

3

I have an MVC controller base class on which I applied the Authorize attribute since I want almost all of the controllers (and their actions along) to be authorized.

However I need to have a controller and an action of another controller unauthorized. I wanted to be able to decorate them with the [Authorize(false)] or something but this is not available.

Any ideas?

+13  A: 

You could create a custom authorisation attribute inheriting from the standard AuthorizeAttribute with an optional bool parameter to specify whether authorisation is required or not.

public class OptionalAuthorizeAttribute : AuthorizeAttribute
{
 private readonly bool _authorize;

 public OptionalAuthorizeAttribute()
 {
  _authorize = true;
 }

 public OptionalAuthorizeAttribute(bool authorize)
 {
  _authorize = authorize;
 }

 protected override bool AuthorizeCore(HttpContextBase httpContext)
 {
  if(!_authorize)
   return true;

                    return base.AuthorizeCore(httpContext);
 }
}

Then you can decorate your base controller with that attribute:

[OptionalAuthorize]
public class ControllerBase : Controller
{
}

and for any controllers you don't want authorisation simply use the override with a 'false' - e.g.

[OptionalAuthorize(false)]
public class TestController : ControllerBase
{
 public ActionResult Index()
 {
  return View();
 }
}
Steve Willcock
I have thought of this but I was hoping for a simpler solution. However if "they" didn't provide one then your solution is the best one.
Andrei Rinea
+3  A: 

My personal take on this would be to split the controller. Just create another controller For the actions you don't need authentication.

Or you could have :

BaseController - doesn't require authentication - here you have all your "base stuff" :).

BaseAuthController : BaseController - all actions here require authentication.

That way you can have authentication when you want , just by deriving from a specific class.

sirrocco
+3  A: 

If you just want one action to be unauthorized on an otherwise authorized controller you can do something like this:

public class RequiresAuthorizationAttribute : ActionFilterAttribute
{
    private readonly bool _authorize;

    public RequiresAuthorizationAttribute()
    {
     _authorize = true;
    }

    public RequiresAuthorizationAttribute(bool authorize)
    {
     _authorize = authorize;
    }

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
     var overridingAttributes = filterContext.ActionDescriptor.GetCustomAttributes(typeof (RequiresAuthorizationAttribute), false);

     if (overridingAttributes.Length > 0 && overridingAttributes[0] as RequiresAuthorizationAttribute != null && !((RequiresAuthorizationAttribute)overridingAttributes[0])._authorize)
      return;

     if (_authorize)
     {
      //redirect if not authenticated
      if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
      {
       //use the current url for the redirect
       var redirectOnSuccess = filterContext.HttpContext.Request.Url.AbsolutePath;

       //send them off to the login page
       //var redirectUrl = string.Format("?RedirectUrl={0}", redirectOnSuccess);
       var loginUrl = LinkBuilder.BuildUrlFromExpression<HomeController>(filterContext.RequestContext, RouteTable.Routes,
                                                                         x => x.Login(redirectOnSuccess));
       filterContext.HttpContext.Response.Redirect(loginUrl, true);
      }
     }
    }
}
bingle