Question

I have a simple ASP.Net MVC 3 application that has some controller and a good few actions.

Now, as this is a user based application, most of the controller actions require the user to be authenticated. MVC handles this well with the built-in Authorize attribute which you can use to decorate controllers and/or actions individually.

The great thing is you can apply the attribute to just the controller and all actions for that given controller will have it applied too - lots of typing saved ;)

But I have one controller with, lets say, 10 actions. But I want one of the actions to not have the Authorize attribute applied.

Yes, I could apply the attribute to the other 9 and remove it from the controller which will do exactly what I need. But is there a way to keep it applied to the controller and just choose to exclude one of the actions?

Effectively, would want something like...

[!Authorize] or [NotAuthorize]

I know I could create a custom one that will do the job, but what I want to know is if there is a built-in way to do this? or do I have to apply the attribute to all 9 other actions?

Was it helpful?

Solution

Phil Haack wrote a blog post recently dealing with this exact scenario:

Conditional Filters in ASP.NET MVC 3

His solution includes writing a custom "conditional filter provider" that allows one to designate a filter condition to attributes of an action method.

The details and reasoning are in his post, but the code is relatively simple. First, create the filter provider:

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

public class ConditionalFilterProvider : IFilterProvider {
  private readonly 
    IEnumerable<Func<ControllerContext, ActionDescriptor, object>> _conditions;

  public ConditionalFilterProvider(
    IEnumerable<Func<ControllerContext, ActionDescriptor, object>> conditions)
  {

      _conditions = conditions;
  }

  public IEnumerable<Filter> GetFilters(
      ControllerContext controllerContext, 
      ActionDescriptor actionDescriptor) {
    return from condition in _conditions
           select condition(controllerContext, actionDescriptor) into filter
           where filter != null
           select new Filter(filter, FilterScope.Global, null);
  }
}

And then applying it:

IEnumerable<Func<ControllerContext, ActionDescriptor, object>> conditions = 
    new Func<ControllerContext, ActionDescriptor, object>[] { 

    (c, a) => c.Controller.GetType() != typeof(HomeController) ? 
      new MyFilter() : null,
    (c, a) => a.ActionName.StartsWith("About") ? new SomeFilter() : null
};

var provider = new ConditionalFilterProvider(conditions);
FilterProviders.Providers.Add(provider);

OTHER TIPS

Note that a new attribute has been added in ASP.NET MVC 4.0 that does exactly that:
[AllowAnonymous]

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top