ASP.NET MVC Global or BaseController ActionFilter to Execute Before OnAuthorization

Nick Olsen picture Nick Olsen · Sep 15, 2011 · Viewed 10.2k times · Source

In my application (ASP.NET MVC 3) I have a BaseController class that all my Controllers inherit and in that BaseController I have overridden the OnActionExecuting method to check to ensure a Session variable is populated as I need access to that in all other action methods in the application. I also have a custom Authorize attribute that I have defined that extends the AuthorizeAttributeClass. In that attribute I override OnAuthorization to check the same Session variable I am loading in the BaseController OnActionExecuting method to see if the user should be permitted to continue.

BaseController

public class BaseController : Controller
{
    private ISessionUserService sessionUserService;

    public BaseController(ISessionUserService sessionUserService)
    {
        this.sessionUserService = sessionUserService;            
    }

    protected override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        base.OnActionExecuting(filterContext);

        if (User != null && User.Identity.IsAuthenticated && this.sessionUserService.Current == null)
        {                     
            this.sessionUserService.Start(accountID, User.Identity.Name);                                                                           

            // If we weren't successful in reloading the SessionUser
            // variable, redirect the user to the Sign In view
            if (this.sessionUserService.Current == null)
            {                  
                filterContext.Result = new RedirectResult(Url.Action("SignIn", "Access", new { area = string.Empty }));
                return;
            }
        }
    }

}

Custom Authorize Attribute

public class AuthorizeByPermission : AuthorizeAttribute
{        
    public Permission[] Permissions { get; set; }

    public AuthorizeByPermission(params Permission[] permissions)
    {
        this.Permissions = permissions;
    }

    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        base.OnAuthorization(filterContext);

        SessionUser sessionUser = filterContext.HttpContext.Session.Get<SessionUser>();

        if (sessionUser.HasPermission(Permissions))
            return;

        filterContext.Result = new HttpUnauthorizedResult();
    }
}

The problem is that the BaseController OnActionExecuting method is firing AFTER the OnAuthorization method in my AuthorizeByPermission attribute and I need it to be the other way arround as the BaseController needs to popualte the Session variable if it isn't there before the authorize attribute attempts to access it.

Basically I need to find a way to have a base class method or a global filter that can be registered to occur before the OnAuthorization method fires. Any ideas on how to do this?

I have tried registering a GlobalFilter to load the session variable and set its Order property to be lower than the AuthorizeByPermission attribute but that didn't seem to work either.

I have also tried overriding the Execute method in the BaseController and that actually fired before the custom authorization attribute but the problem was that I didn't have access to the filterContext which allowed me to redirect the user to the SignIn page if we couldn't load the session variable.

As per bmosh's comment I tried turning my BaseController OnActionExecuting method into a separate filter and decorate the BaseController with that attribute with a lower Order number than the AuthorizeByPermission attribute but it still didn't work.

[FilterIWantToFireFirst(Order = 1)]
public class BaseController : Controller
{

}

public class AnotherController : BaseController
{
     [AuthorizeByPermission(Permission.Add, Order = 2)]
     public ActionResult SomeActionMethod() 
     {
     }
}

Even with the above setup, the AuthorizeByPermission attribute is fired first.

Any ideas?

Answer

Trax72 picture Trax72 · Oct 11, 2011

You could try overriding OnAuthorization instead of OnActionExecuting in your base controller.