一种在MVC 4应用程序中正确处理HttpAntiForgeryException的方法

Mar*_*cin 35 c# asp.net-mvc antiforgerytoken

这是场景:

我有一个登录页面,当用户签名时,它会被重定向到主页应用程序页面.然后用户使用浏览器后退按钮,现在他在登录页面上.他尝试再次登录,但现在抛出异常:

HttpAntiForgeryException(0x80004005):提供的防伪令牌适用于用户"",但当前用户是"userName".

我知道这与缓存有关.我使用自定义NoCache过滤器禁用了浏览器缓存以进行登录操作,该过滤器设置了所有必需的标头 - 无缓存,无存储,必须重新验证等.但是

  • 这不适用于所有浏览器
  • 特别是Safari(在大多数情况下是移动设备)完全忽略了这样的设置

我将尝试制作黑客并强制Safari移动刷新,但这不是我所期待的.

我想知道我是否可以:

  • 处理异常而不显示用户存在任何问题(对用户完全透明)
  • 通过更换防伪造令牌的用户名防止这个问题,这将再次允许用户登录没有这个例外,如果我涉及到浏览器的缓存黑客会在浏览器的下一个版本中停止工作.
  • 我真的不想依赖浏览器行为,因为每个行为都不同.

更新1

为了澄清一下,我知道如何处理MVC中的错误.问题是这个处理错误根本解决了我的问题.错误处理的基本思想是重定向到自定义错误页面,并带有好消息.但我希望防止发生此错误,而不是以用户可见的方式处理它.通过句柄我的意思是捕获用户名替换或其他合适的操作然后继续登录.

更新2

我添加了下面的解决方案,这对我有用.

Mar*_*cin 19

经过一段时间的调查后,我想我找到了一些方法来解决用户的这个错误.它不完美,但至少没有显示错误页面:

我根据创建的过滤器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
    }
Run Code Online (Sandbox Code Playgroud)

然后我将此过滤器应用于Login POST操作:

[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
[LoginAntiforgeryHandleError]
public ActionResult Login(Login model, string returnUrl)
{
Run Code Online (Sandbox Code Playgroud)

此解决方案的主要思想是将防伪异常重定向到主索引操作.如果用户仍未进行未经身份验证,则会显示登录页面,如果用户已经过身份验证,则会显示索引页面.

更新1 此解决方案存在一个潜在问题.如果有人使用不同的凭据登录,那么在出错时应该添加其他登录运行时 - 注销以前的用户并登录新用户.此方案未得到处理.


Cry*_*pth 19

如果您只有一个或几个功能受到影响,那么创建过滤器可能会略微技术性过度.一个更简单但非通用的解决方案是简单地删除[ValidateAntiForgeryToken]特定方法,并在检查用户是否登录后添加手动验证.

if (User.Identity.IsAuthenticated)
{
    return RedirectToAction("Index", "Home");
}
System.Web.Helpers.AntiForgery.Validate();
/* proceed with authentication here */
Run Code Online (Sandbox Code Playgroud)

  • 正是@AmrElgarhy,现在您可以抓住它! (2认同)

Jos*_*nke 5

您应该能够通过添加操作过滤器来处理错误来处理异常.

[HandleError(View="AntiForgeryExceptionView", ExceptionType = typeof(HttpAntiForgeryException))]
Run Code Online (Sandbox Code Playgroud)

Todo因此请确保在web.config中打开自定义错误.

<customErrors mode="On"/>
Run Code Online (Sandbox Code Playgroud)

您还可以查看此博客,了解有关句柄错误的更多信息.

编辑因为您正在使用MVC4而博客是关于MVC3的,所以您还可以查看MSDN库--HandleErrorAttribute,但该版本不应该有所作为.