简体   繁体   中英

MVC 3 API custom response body on error

I'm trying to write an API with a login method + others. When there is an issue logging in, I would like to return a custom HTTP error code to the client with a custom response body. The problem is that on error the request is getting redirected to the home page.

[HttpPost]
[AllowAnonymous]
public JsonResult ApiLogIn(LoginModel model)
{
    if (ModelState.IsValid)
    {
        var outcome = _authService.LogIn(model);

        if (outcome == LogInOutcome.Success)
        {
            return Json(new { }); // Empty on success
        }
        else
        {
            Response.StatusCode = (int)HttpStatusCode.Unauthorized;
            return Json(new { reason = outcome.ToString() });
        }
    }

    Response.StatusCode = (int)HttpStatusCode.BadRequest;
    return Json(new { }); // Empty or invalid model
}

How do I stop it from getting redirected on error?

The issue is the fact that late in the request lifecycle, the FormsAuth module checks to see if the Response.StatusCode is 401, and if so, redirects to the login page.

You can try a different status code (like 403, granted that's not quite appropriate for your scenario). The other option is to delay setting the Response.StatusCode to 401 until the EndRequest event in your Global.asax.

I solved this by adding a flag into Context.Items and checking for the presence of the flag in EndRequest :

Global.asax.cs - Add this method

protected void Application_EndRequest(Object sender, EventArgs e)
{
    if(Context.Items["AjaxPermissionDenied"] is bool) // FormsAuth module intercepts 401 response codes and does a redirect to the login page. 
    {
        Context.Response.StatusCode = 401;
        Context.Response.StatusDescription = "Permission Denied";
        Context.Response.End();
        return;
    }
}

In your controller

[HttpPost]
[AllowAnonymous]
public JsonResult ApiLogIn(LoginModel model)
{
    if (ModelState.IsValid)
    {
        var outcome = _authService.LogIn(model);

        if (outcome == LogInOutcome.Success)
        {
            return Json(new { }); // Empty on success
        }
        else
        {
            Context.Items["AjaxPermissionDenied"] = true;
            return Json(new { reason = outcome.ToString() });
        }
    }

    Response.StatusCode = (int)HttpStatusCode.BadRequest;
    return Json(new { }); // Empty or invalid model
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM