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

Как mvc вернуть неавторизованный код без перенаправления на просмотр журнала

В моем веб-приложении MVC используются два типа пользователей.

  • Первый в стандартном веб-браузере;
  • Второй для REST, возвращающий только данные JSON.

Кроме того,

  • Оба требуют аутентификации и авторизации;
  • Оба сценария дифференцируются в зависимости от маршрута, поэтому я знаю, какой контент должен обслуживаться.

Когда пользователи обращаются к приложению, если они не вошли в систему, приложение должно реагировать по-разному.

  • В первом случае он должен вернуть страницу входа в систему по умолчанию (это нормально).
  • Во втором случае он должен вернуть только 401 неавторизованный код.

Я привык работать с сервисом WCF REST, где я мог бы создать такое исключение:

throw new WebProtocolException(System.Net.HttpStatusCode.Unauthorized, exc.Message, exc);

и получите сообщение 401. Проблема с тем же подходом в MVC, когда я помещаю statusCode следующим образом:

HttpContext.Response.StatusCode = (Int32)HttpStatusCode.Unauthorized

он всегда перенаправляется на страницу входа в систему.

Как я могу это сделать?

Я попытался переопределить AuthorizeAttribute и обработать функцию OnAuthorization, но все же, как только я установил statusCode в 401, он перенаправляется на страницу входа в систему.

4b9b3361

Ответ 1

Чтобы предотвратить перенаправление страницы входа, вы должны установить для свойства SuppressFormsAuthenticationRedirect значение HttpContext.Response значение true:

 HttpContext.Response.SuppressFormsAuthenticationRedirect = true;

Ответ 2

То, что вы испытываете, - это дыра в ASP.NET MVC (надеюсь, они исправит один день).

Стандартная операционная модель для ASP.NET заключается в том, что если обнаружен код состояния 401 Http, то, как вы переживаете, он автоматически перенаправляется на страницу входа в систему, и это происходит, даже если вы вошли через вызов Ajax. К сожалению, я также не нашел способа изменить это поведение.

Вместо этого я верю альтернативу, иначе неиспользуемый код состояния Http, который я могу обнаружить на клиенте и обработать соответствующим образом.

Поэтому в моем Фильтре проверки подлинности, если его запрос Ajax возвращает 449, в противном случае стандарт 401. Тогда на клиенте я могу проверить XMLHttpRequest.status и предпринять соответствующие действия, если обнаружено 449.

Ответ 3

Вы можете создать простой фильтр атрибутов авторизации (расширить класс AuthorizeAttribute) и использовать его для вашего контроля доступа. Затем попробуйте что-то вроде этого:

protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
    if (filterContext.HttpContext.Request.IsAjaxRequest() ||  string.Compare("GET", filterContext.HttpContext.Request.HttpMethod, true) != 0)
    {
        // Returns 403.
        filterContext.Result = new HttpStatusCodeResult((int)HttpStatusCode.Forbidden);
    }
    else
    {
        // Returns 401.
        filterContext.Result = new HttpUnauthorizedResult();
    }
}

Эффект заключается в том, что запросы POST и AJAX всегда получат ответ 403, который облегчает вам обработку ваших аякс-представлений в javascript. Что касается сообщений, отличных от ajax, на самом деле не имеет значения, каков ответ, потому что ваш пользователь не должен иметь руки на форме отправки в первую очередь:)

Как и для других запросов, метод возвращает 401, что модуль formsAuthentiction подберет, а затем перенаправит ваш ответ на страницу входа.

Ответ 4

Так мне удалось предотвратить перенаправление на страницу входа.

В моем случае, когда я хотел получить код состояния, чтобы обработать его в javascript:

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

Ответ 5

Я работаю над веб-приложением, которое также предоставляет веб-api, и я не вижу этого поведения.

Когда вы используете REST, вам нужен механизм для аутентификации пользователя, выдающего запрос для тех конечных точек/ресурсов, которые не являются общедоступными.

Этот механизм может быть:

  • Отправка ваших учетных данных с каждым запросом. Обычно используется Http Basic Authentication.
  • Вывести конечную точку аутентификации, которая может быть удалена один раз с помощью надлежащих учетных данных, и в результате пользователь получит маркер/билет, если аутентификация выполнена успешно.

Если вы собираетесь использовать второй вариант, есть альтернативы от простого к сложному, что сделает ваше решение более или менее надежным. Amazon way хорошо известен и правильно документирован. Однако иногда отправлять только токен в виде заголовка с использованием https достаточно, если ваши данные не так чувствительны.

Независимо от того, используете ли вы базовую HTTP-аутентификацию или самый безопасный механизм аутентификации в мире, вам понадобится что-то, которое проверяет, что вы отправляете по каждому запросу, и заполняет Принципала в контексте запрос.

Это что-то может быть достигнуто в Asp.net Web Api с обработчиком сообщений, а также делегациейHandler, которая будет сидеть и обрабатывать каждый запрос вашим контроллерам api и заполнять своего Принципала или нет, основываясь на найденной им информации аутентификации.

Вы можете найти пример реализации DelegatingHandler здесь

После установки этой инфраструктуры вы сможете использовать Syste.Web.Http.AuthorizeAttribute aka [Авторизовать] на уровне контроллера api или на уровне действия, согласно вашему необходимо.

Вы должны получить 401 Unauthorized без перенаправления, если DelegatingHandler не может заполнить основную информацию, предоставленную с помощью имеющейся у нее информации об аутентификации.

Не забудьте зарегистрировать свой DelegatingHandler в App_Start.

Ответ 6

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