Способ правильной обработки HttpAntiForgeryException в приложении MVC 4
вот сценарий:
У меня есть страница входа в систему, при входе пользователя он перенаправляется на домашнюю страницу приложения. Затем пользователь использует кнопку возврата браузера, и теперь он находится на странице входа в систему. Он пытается снова войти в систему, но теперь возникает исключение:
HttpAntiForgeryException (0x80004005): предоставленный токен защиты от подделки предназначен для пользователя "", но текущий пользователь-"userName".
Я знаю, что это связано с кэшированием. У меня браузер отключен кэширование для действия входа с помощью настраиваемого фильтра NoCache, который устанавливает все необходимые заголовки-no-cache,no-store, must-revalidate и т. д. Но!--1-->
- это не работает на всех браузерах
- особенно Safari (мобильный в большинстве случаев) полностью игнорирует такие настройки
Я попытаюсь сделать хаки и заставить safari mobile обновиться, но это не то, что я ожидаю.
Я хотел бы знать, могу ли я:
- ручки исключение без показа пользователю любой проблемы существует (полностью прозрачный для пользователя)
- предотвратите эту проблему, заменив имя пользователя токена Anti forgery что позволит пользователю войти снова без этого исключения, если мои хаки, связанные с кэшированием браузера, перестанут работать в следующих версиях браузеров.
- Я действительно не хотел бы полагаться на поведение браузера, так как каждый ведет себя по-разному.
обновление 1
чтобы сделать некоторые разъяснения, я знаю, как обрабатывать ошибки в MVC. Проблема в том, что эта обработка ошибок не решает мою проблему вообще. Основная идея обработки ошибок-перенаправление на пользовательскую страницу ошибок с приятным сообщением. Но я хочу предотвратить эту ошибку, а не обрабатывать ее видимым для пользователя способом. Под ручкой я имею в виду catch make username replace или другое подходящее действие, а затем продолжить вход в систему.
обновление 2
Я добавил ниже решение, которое работает для меня.
4 ответов
после некоторого времени исследования я думаю, что нашел способ избавиться от этой ошибки для пользователя. Это не идеально, но, по крайней мере, не отображать страницу ошибки:
Я создал фильтр на основе HandleErrorAttribute
:
[SuppressMessage("Microsoft.Performance", "CA1813:AvoidUnsealedAttributes",
Justification = "This attribute is AllowMultiple = true and users might want to override behavior.")]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false)]
public class LoginAntiforgeryHandleErrorAttribute : FilterAttribute, IExceptionFilter
{
#region Implemented Interfaces
#region IExceptionFilter
/// <summary>
/// </summary>
/// <param name="filterContext">
/// The filter context.
/// </param>
/// <exception cref="ArgumentNullException">
/// </exception>
public virtual void OnException(ExceptionContext filterContext)
{
if (filterContext == null)
{
throw new ArgumentNullException("filterContext");
}
if (filterContext.IsChildAction)
{
return;
}
// If custom errors are disabled, we need to let the normal ASP.NET exception handler
// execute so that the user can see useful debugging information.
if (filterContext.ExceptionHandled || !filterContext.HttpContext.IsCustomErrorEnabled)
{
return;
}
Exception exception = filterContext.Exception;
// If this is not an HTTP 500 (for example, if somebody throws an HTTP 404 from an action method),
// ignore it.
if (new HttpException(null, exception).GetHttpCode() != 500)
{
return;
}
// check if antiforgery
if (!(exception is HttpAntiForgeryException))
{
return;
}
filterContext.Result = new RedirectToRouteResult(
new RouteValueDictionary
{
{ "action", "Index" },
{ "controller", "Home" }
});
filterContext.ExceptionHandled = true;
}
#endregion
#endregion
}
затем я применил этот фильтр для входа в действие POST:
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
[LoginAntiforgeryHandleError]
public ActionResult Login(Login model, string returnUrl)
{
основная идея этого решения состоит в том, чтобы перенаправить исключение анти-подделки на основное действие индекса. Если пользователь все равно не будет аутентифицирован, он покажетлогин страница если пользователь будет уже аутентифицирован, он покажет индекс
Если у вас есть только одна или несколько функций, создание фильтра может быть немного техническим перебором. Более простое, но не общее решение-просто удалить [ValidateAntiForgeryToken]
для конкретного метода и добавление ручной проверки, после проверки, если пользователь вошел в систему.
if (User.Identity.IsAuthenticated)
{
return RedirectToAction("Index", "Home");
}
System.Web.Helpers.AntiForgery.Validate();
/* proceed with authentication here */
вы должны иметь возможность обрабатывать исключение, добавляя фильтр действий для обработки вашей ошибки.
[HandleError(View="AntiForgeryExceptionView", ExceptionType = typeof(HttpAntiForgeryException))]
Todo поэтому убедитесь, что пользовательские ошибки включены в вашем интернете.конфиг.
<customErrors mode="On"/>
вы также можете взглянуть на это блог для получения дополнительной информации об ошибке обработки.
редактировать так как вы используете MVC4 и блог о MVC3 вы также можете взглянуть на библиотека MSDN-HandleErrorAttribute, но версия не должна иметь никакого значения.
старый вопрос-но я столкнулся с этой проблемой сегодня, и то, как я ее решил, было перенаправлением на действие выхода:
public ActionResult Login(string returnUrl)
{
if (WebSecurity.IsAuthenticated)
return RedirectToAction("LogOff");
...
}