Professional Programmer Notes

or just call this my soapbox

Archive for March 2010

Two ways to handle unauthorized requests to Ajax actions in ASP.NET MVC 2

leave a comment »

Problem:  I have created a view that posts to an action via Ajax with the expectation that the action will return the requested data or an empty string.  Even better, I would like it to be configurable to return whatever value I see fit.

The problem arises when I decorate the called action with the [Authorize] attribute.  If the request is not authorized and I have a loginUrl configured in my web.config, my ajax request will return the html output of my loginUrl view.  That is undesirable.

Solution #1:  I need to implement a custom ActionFilterAttribute that I can use on the ajax action to handle the request appropriately.  Here is the code for my ActionFilterAttribute:

    public class AjaxAuthorizeAttribute : ActionFilterAttribute
    {
        public string View { get; set; }
        private bool renderView;

        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            if (!filterContext.HttpContext.Request.IsAuthenticated && filterContext.HttpContext.Request.IsAjaxRequest())
            {
                renderView = true;
            }

            base.OnActionExecuting(filterContext);
        }

        public override void OnResultExecuting(ResultExecutingContext filterContext)
        {
            if (renderView)
            {
                filterContext.Result = new ViewResult { ViewName = View };
                filterContext.Result.ExecuteResult(filterContext.Controller.ControllerContext);
                return;
            }

            base.OnResultExecuting(filterContext);
        }
    }

And, here is how I would decorate my ajax action in my controller class:

	[AjaxAuthorize(View="AjaxAuthorizeError")]
public ActionResult AjaxRequest()
{
        return View();
}

That would handle the issue by checking whether the request is authenticated.  If it isn’t authenticated and the request is being submitted via ajax, a specified view will get called.  The content of that view determines what my ajax call will receive back when the request is not authenticated.

Note:  There is no default view page being rendered if one is not passed to the ActionFilterAttribute.  That’s room for improvement.

Solution #2:  I can extend the existing Authorize attribute by inheriting from the AuthorizeAttribute class.  Here is the code that extends the Authorize attribute:

    public class AjaxAuthorizeOverrideAttribute : AuthorizeAttribute
    {
        public string View { get; set; }

        protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
        {
            if (!filterContext.HttpContext.Request.IsAjaxRequest())
            {
                base.HandleUnauthorizedRequest(filterContext);
                return;
            }

            filterContext.Result = new ViewResult { ViewName = View };
            filterContext.Result.ExecuteResult(filterContext.Controller.ControllerContext);
        }
    }

Here is the decorator for the ajax action in the controller class:

[AjaxAuthorizeOverride(View="AjaxAuthorizeError")]
public ActionResult AjaxRequest()
{
     return View();
}

Note:  Again, there is no default view page being rendered.

Written by curtismitchell

March 22, 2010 at 4:10 pm

Posted in Uncategorized