views:

1296

answers:

2

I have a controller and I would like to require Authorization for all actions by default except a couple. So in the example below all actions should require authentication except the Index. I don't want to decorate every action with the Authorize, I just want to override the default authorization in certain circumstances probably with a custom filter such as NotAuthorize.

[Authorize]
public class HomeController : BaseController
{
    [NotAuthorize]
    public ActionResult Index()
    {
        // This one wont
        return View();
    }

    public ActionResult About()
    {
        // This action will require authorization
        return View();
    }
}
+8  A: 

Ok, this is what I did. If there is a better way let me know.

public class NotAuthorizeAttribute : FilterAttribute
{
    // Does nothing, just used for decoration
}

public class BaseController : Controller
{
    protected override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        // Check if this action has NotAuthorizeAttribute
        object[] attributes = filterContext.ActionDescriptor.GetCustomAttributes(true);
        if (attributes.Any(a => a is NotAuthorizeAttribute)) return;

        // Must login
        if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
        {
            filterContext.Result = new HttpUnauthorizedResult();
        }
    }
}
Craig
+1  A: 

Here's what I would do, similar to Craig's answer with a couple of changes:

1) Create an ordinary attribute deriving from System.Attribute (no need to derive from FilterAttribute since you aren't going to be using anything FilterAttribute provides).

Maybe create a class hierarchy of attributes so you can test based on the hierarchy, e.g.

Attribute
    AuthorizationAttribute
         AuthorizationNotRequiredAttribute
         AuthorizationAdminUserRequiredAttribute
             AuthorizationSuperUserRequiredAttribute

2) In your BaseController override the OnAuthorization method rather than the OnActionExecuting method:

protected override void OnAuthorization(AuthorizationContext filterContext)
{
    var authorizationAttributes = filterContext.ActionDescriptor.GetCustomAttributes(true).OfType<AuthorizationAttribute>();
    bool accountRequired = !authorizationAttributes.Any(aa => aa is AuthorizationNotRequiredAttribute);

I like the approach of being secure by default: even if you forget to put an attribute on the Action it will at least require a user to be logged in.

Hightechrider
if i override OnAuthorization(AuthorizationContext filterContext), filterContext has no ActionDescriptor property, so i have no idea how to find the custom attributes from filterContext?
spaceman
Can you confirm this is ASP.NET MVC 2? There's definitely an ActionDescriptor there in V2.
Hightechrider
Sorry man, you're correct, I'm not running MVC 2 yet.
spaceman
installed mvc 2 and the code is running, i get inside my onAuthorisation overload, check for my attribute and if its found then return.it then still redirects to the login page after i return out of the onAuth method?EDIT : nvm its because i still had the authorise attribute on my controlelr
spaceman