Подтвердить что ты не робот

401 код ответа для запросов json с ASP.NET MVC

Как отключить стандартную обработку ASP.NET кода ответа 401 (перенаправление на страницу входа) для запросов AJAX/JSON?

Для веб-страниц это нормально, но для AJAX мне нужно получить правильный код ошибки 401 вместо хорошего 302/200 для страницы входа.

Обновление: Существует несколько решений от Phil Haack, PM ASP.NET MVC - http://haacked.com/archive/2011/10/04/prevent-forms-authentication-login-page-redirect-when-you-donrsquot-want.aspx

4b9b3361

Ответ 1

Время выполнения ASP.NET разрабатывается так, что оно всегда будет перенаправлять пользователя, если для параметра HttpResponse.StatusCode установлено значение 401, но только если найден раздел <authentication /> в файле Web.config.

Удаление раздела аутентификации потребует от вас перенаправления на страницу входа в ваш атрибут, но это не должно быть большой проблемой.

Ответ 2

В классическом ASP.NET вы получаете код ответа 401 http при вызове WebMethod с Ajax. Я надеюсь, что они изменят его в будущих версиях ASP.NET MVC. Прямо сейчас я использую этот хак:

protected void Application_EndRequest()
{
    if (Context.Response.StatusCode == 302 && Context.Request.Headers["X-Requested-With"] == "XMLHttpRequest")
    {
        Context.Response.Clear();
        Context.Response.StatusCode = 401;
    }
}

Ответ 3

Мне нужна была и проверка подлинности форм, и возврат 401 для Ajax-запросов, которые не были аутентифицированы.

В конце концов, я создал специальный атрибут AuthorizeAttribute и украсил методы контроллера. (Это находится на .Net 4.5)

//web.config

<authentication mode="Forms">
</authentication>

//контроллер

[Authorize(Roles = "Administrator,User"), Response302to401]
[AcceptVerbs("Get")]
public async Task<JsonResult> GetDocuments()
{
    string requestUri = User.Identity.Name.ToLower() + "/document";
    RequestKeyHttpClient<IEnumerable<DocumentModel>, string> client =
        new RequestKeyHttpClient<IEnumerable<DocumentModel>, string>(requestUri);

    var documents = await client.GetManyAsync<IEnumerable<DocumentModel>>();

    return Json(documents, JsonRequestBehavior.AllowGet);
}

//authorizeAttribute

public class Response302to401 : AuthorizeAttribute
{
    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
    {
        if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
        {
            if (filterContext.HttpContext.Request.IsAjaxRequest())
            {
                filterContext.Result = new JsonResult
                {
                    Data = new { Message = "Your session has died a terrible and gruesome death" },
                    JsonRequestBehavior = JsonRequestBehavior.AllowGet
                };
                filterContext.HttpContext.Response.StatusCode = 401;
                filterContext.HttpContext.Response.StatusDescription = "Humans and robots must authenticate";
                filterContext.HttpContext.Response.SuppressFormsAuthenticationRedirect = true;
            }
        }
        //base.HandleUnauthorizedRequest(filterContext);
    }
}

Ответ 4

Вы также можете использовать Global.asax, чтобы прервать этот процесс примерно следующим образом:

    protected void Application_PreSendRequestHeaders(object sender, EventArgs e) {
        if (Response.StatusCode == 401) {
            Response.Clear();
            Response.Redirect(Response.ApplyAppPathModifier("~/Login.aspx"));
            return;
        }
    }

Ответ 5

Я не вижу, что нам нужно изменить режим аутентификации или тег проверки подлинности, как говорит текущий ответ.

Следуя идее @TimothyLeeRussell (спасибо, кстати), я создал настраиваемый атрибут Authorize (проблема с именем @TimothyLeeRussell заключается в том, что исключение выбрано потому, что он пытается изменить filterContext.Result a, который генерирует HttpException и удаляя эту часть, помимо фильтраContext.HttpContext.Response.StatusCode = 401, код ответа всегда был 200 OK). Поэтому я, наконец, решил проблему, завершив ответ после изменений.

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class BetterAuthorize : AuthorizeAttribute
{
    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
    {
        if (filterContext.HttpContext.Request.IsAjaxRequest())
        {
            //Set the response status code to 500
            filterContext.HttpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
            filterContext.HttpContext.Response.StatusDescription = "Humans and robots must authenticate";
            filterContext.HttpContext.Response.SuppressFormsAuthenticationRedirect = true;

            filterContext.HttpContext.Response.End();
        }
        else
            base.HandleUnauthorizedRequest(filterContext);
    }
}

Ответ 6

Вы можете создать пользовательский FilterAttribute интерфейс IAuthorizationFilter.

В этом атрибуте вы добавляете логику, чтобы определить, должен ли запрос возвращать JSON. Если это так, вы можете вернуть пустой результат JSON (или сделать что угодно), если пользователь не подписан. Для других ответов вы просто перенаправляете пользователя, как всегда.

Еще лучше, вы можете просто переопределить OnAuthorization класса AuthorizeAttribute, чтобы вам не пришлось изобретать колесо. Добавьте логику, упомянутую выше, и перехватите, если значение filterContext.Cancel истинно (filterContext.Result будет установлено в экземпляр класса HttpUnauthorizedResult.

Подробнее о "Фильтры в ASP.NET MVC CodePlex Preview 4" в блоге Phil Haacks. Это также относится к последнему превью.

Ответ 7

Вы можете вызвать этот метод внутри своего действия,

 HttpContext.Response.End();

Пример

public async Task<JsonResult> Return401()
{
    HttpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
    HttpContext.Response.End();
    return Json("Unauthorized", JsonRequestBehavior.AllowGet);
}

От MSDN: метод End заставляет веб-сервер прекратить обработку script и вернуть текущий результат. Оставшееся содержимое файла не обрабатывается.