Ответ 1
Чтобы предотвратить перенаправление страницы входа, вы должны установить для свойства SuppressFormsAuthenticationRedirect
значение HttpContext.Response
значение true:
HttpContext.Response.SuppressFormsAuthenticationRedirect = true;
В моем веб-приложении MVC используются два типа пользователей.
Кроме того,
Когда пользователи обращаются к приложению, если они не вошли в систему, приложение должно реагировать по-разному.
Я привык работать с сервисом 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, он перенаправляется на страницу входа в систему.
Чтобы предотвратить перенаправление страницы входа, вы должны установить для свойства SuppressFormsAuthenticationRedirect
значение HttpContext.Response
значение true:
HttpContext.Response.SuppressFormsAuthenticationRedirect = true;
То, что вы испытываете, - это дыра в ASP.NET MVC (надеюсь, они исправит один день).
Стандартная операционная модель для ASP.NET заключается в том, что если обнаружен код состояния 401 Http, то, как вы переживаете, он автоматически перенаправляется на страницу входа в систему, и это происходит, даже если вы вошли через вызов Ajax. К сожалению, я также не нашел способа изменить это поведение.
Вместо этого я верю альтернативу, иначе неиспользуемый код состояния Http, который я могу обнаружить на клиенте и обработать соответствующим образом.
Поэтому в моем Фильтре проверки подлинности, если его запрос Ajax возвращает 449, в противном случае стандарт 401. Тогда на клиенте я могу проверить XMLHttpRequest.status и предпринять соответствующие действия, если обнаружено 449.
Вы можете создать простой фильтр атрибутов авторизации (расширить класс 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 подберет, а затем перенаправит ваш ответ на страницу входа.
Так мне удалось предотвратить перенаправление на страницу входа.
В моем случае, когда я хотел получить код состояния, чтобы обработать его в javascript:
protected void Application_EndRequest()
{
if (Context.Response.StatusCode == 302 && Context.Request.Headers["X-Requested-With"] == "XMLHttpRequest")
{
Context.Response.Clear();
Context.Response.StatusCode = 401;
}
}
Я работаю над веб-приложением, которое также предоставляет веб-api, и я не вижу этого поведения.
Когда вы используете REST, вам нужен механизм для аутентификации пользователя, выдающего запрос для тех конечных точек/ресурсов, которые не являются общедоступными.
Этот механизм может быть:
Если вы собираетесь использовать второй вариант, есть альтернативы от простого к сложному, что сделает ваше решение более или менее надежным. Amazon way хорошо известен и правильно документирован. Однако иногда отправлять только токен в виде заголовка с использованием https достаточно, если ваши данные не так чувствительны.
Независимо от того, используете ли вы базовую HTTP-аутентификацию или самый безопасный механизм аутентификации в мире, вам понадобится что-то, которое проверяет, что вы отправляете по каждому запросу, и заполняет Принципала в контексте запрос.
Это что-то может быть достигнуто в Asp.net Web Api с обработчиком сообщений, а также делегациейHandler, которая будет сидеть и обрабатывать каждый запрос вашим контроллерам api и заполнять своего Принципала или нет, основываясь на найденной им информации аутентификации.
Вы можете найти пример реализации DelegatingHandler здесь
После установки этой инфраструктуры вы сможете использовать Syste.Web.Http.AuthorizeAttribute aka [Авторизовать] на уровне контроллера api или на уровне действия, согласно вашему необходимо.
Вы должны получить 401 Unauthorized без перенаправления, если DelegatingHandler не может заполнить основную информацию, предоставленную с помощью имеющейся у нее информации об аутентификации.
Не забудьте зарегистрировать свой DelegatingHandler в App_Start.
Вы можете использовать метод OnRedirectToLogin пользователя во время настройки идентификатора.