0

I have created a custom authorization attribute which I have applied to a number of controllers. I now find that I need to handle Ajax requests and gracefully redirect.

Ronnie's answer here looks like exactly what I require, however instead of the JSON object I can only ever get a generic 403 forbidden html page as a result.

SsoAuthorizeAttribute:

public class SsoAuthorizeAttribute : AuthorizeAttribute, IAuthorizationFilter
{
    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext) {
        if (filterContext.HttpContext.Request.IsAjaxRequest()) {
            var urlHelper = new UrlHelper(filterContext.RequestContext);
            filterContext.HttpContext.Response.StatusCode = 403;
            filterContext.Result = new JsonResult {
                Data = new {
                    Error = "NotAuthorized",
                    SingleSignOn = Site.SSOUrl
                },
                JsonRequestBehavior = JsonRequestBehavior.AllowGet
            };
            filterContext.HttpContext.Response.SuppressFormsAuthenticationRedirect = true;
        } else {
            filterContext.Result = new RedirectResult(Site.SSOUrl, false);
        }
    }

    public override void OnAuthorization(AuthorizationContext filterContext) {
        if (true) {
                HandleUnauthorizedRequest(filterContext);
            }
        }
    }
}

Javascript:

$(function () {
    $(document).ajaxError(function (e, xhr) {
        if (xhr.status == 403) {
            //xhr.responseText always contains a generic 403 page instead of the JSON object
            var response = $.parseJSON(xhr.responseText);
            window.location = response.LogOnUrl;
        }
    });
});

If I change the status code to 200:

filterContext.HttpContext.Response.StatusCode = 200;

It works as I would expect.

How do I override the behavior I am experiencing so that I can return the JSON object with a 403 status?

hobwell
  • 538
  • 1
  • 8
  • 26
  • 1
    I've tried your authorization attribute with clean MVC project and I get correct JSON in 403 response. Check whether you have custom error pages configured or some error handler that supplies HTTP error responses with html payload. – CodeFuller Jan 25 '18 at 07:21
  • Thanks for that, led me in the right direction to track down the issue. – hobwell Jan 25 '18 at 21:31

1 Answers1

0

The behavior described in the post is the result of this section of the web config:

<system.webServer>
    <httpErrors errorMode="Custom">
      <remove statusCode="404" />
      <error statusCode="404" path="~/Error/NotFound" responseMode="ExecuteURL" />
      <remove statusCode="500" />
      <error statusCode="500" path="~/Error" responseMode="ExecuteURL" />
    </httpErrors>
</system.webServer>

The presence of that section enables the automatic serving of a generic 403 page (presumably because it has a default path and mode for 403 even if you don't specify one).

Updating the Web.config to include the 403 did not resolve the issue either. That change results in a 404 being thrown instead of a 403 (no clue why this would be).

With custom errors present in the web.config, replacing

filterContext.HttpContext.Response.SuppressFormsAuthenticationRedirect = true;

with

filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;

finally resolved the issue, allowing the 403 to return the Json.

The working code:

protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext) {
    if (filterContext.HttpContext.Request.IsAjaxRequest()) {
        var urlHelper = new UrlHelper(filterContext.RequestContext);
        filterContext.HttpContext.Response.StatusCode = 403;
        filterContext.Result = new JsonResult {
            Data = new {
                Error = "NotAuthorized",
                SingleSignOn = Site.SSOUrl
            },
            JsonRequestBehavior = JsonRequestBehavior.AllowGet
        };
        filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;
    } else {
        filterContext.Result = new RedirectResult(Site.SSOUrl, false);
    }
}

Thanks to @CodeFuller for pointing me in the right direction.

hobwell
  • 538
  • 1
  • 8
  • 26