Craig
Craig

Reputation: 36826

ASP MVC Authorize all actions except a few

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();
    }
}

Upvotes: 31

Views: 32644

Answers (7)

mausinc
mausinc

Reputation: 537

Mark the controller with [Authorize]

[Authorize] public class YourController : ApiController

Mark actions you want public with :

[AllowAnonymous]

Upvotes: 5

Simon_Weaver
Simon_Weaver

Reputation: 146228

MVC4 has a new attribute exactly meant for this [AllowAnonymous] (as pointed out by Enrico)

[AllowAnonymous]
public ActionResult Register()

Read all about it here:

http://blogs.msdn.com/b/rickandy/archive/2012/03/23/securing-your-asp-net-mvc-4-app-and-the-new-allowanonymous-attribute.aspx

Upvotes: 11

Enrico
Enrico

Reputation: 341

What about [AllowAnonymous] ??

Upvotes: 33

Fernando Correia
Fernando Correia

Reputation: 22395

Use a custom filter as described in Securing your ASP.NET MVC 3 Application.

Upvotes: 6

Brian Donahue
Brian Donahue

Reputation: 3082

Little late to the party, but I ended up creating a Controller-level auth attribute and an Action-level auth attribute and just skipping over the Controller auth if the Action had its own Auth attribute. See code here:

https://gist.github.com/948822

Upvotes: 2

Ian Mercer
Ian Mercer

Reputation: 39307

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.

Upvotes: 6

Craig
Craig

Reputation: 36826

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();
        }
    }
}

Upvotes: 41

Related Questions