Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/asp.net-mvc/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# MVC4应用中正确处理HttpAntiforyException的一种方法_C#_Asp.net Mvc_Antiforgerytoken - Fatal编程技术网

C# MVC4应用中正确处理HttpAntiforyException的一种方法

C# MVC4应用中正确处理HttpAntiforyException的一种方法,c#,asp.net-mvc,antiforgerytoken,C#,Asp.net Mvc,Antiforgerytoken,以下是场景: 我有一个登录页面,当用户签名时,它被重定向到主应用程序页面。然后用户使用浏览器返回按钮,现在他进入登录页面。他尝试再次登录,但现在引发异常: HttpAntiforyException(0x80004005):提供的防伪令牌是针对用户“”的,但当前用户是“用户名” 我知道这与缓存有关。我使用自定义NoCache筛选器禁用了登录操作的浏览器缓存,该筛选器设置了所有必需的标题-无缓存、无存储、必须重新验证等,但 这在所有浏览器上都不起作用 尤其是Safari(大多数情况下是移动的)完

以下是场景:

我有一个登录页面,当用户签名时,它被重定向到主应用程序页面。然后用户使用浏览器返回按钮,现在他进入登录页面。他尝试再次登录,但现在引发异常:

HttpAntiforyException(0x80004005):提供的防伪令牌是针对用户“”的,但当前用户是“用户名”

我知道这与缓存有关。我使用自定义NoCache筛选器禁用了登录操作的浏览器缓存,该筛选器设置了所有必需的标题-无缓存、无存储、必须重新验证等,但

  • 这在所有浏览器上都不起作用
  • 尤其是Safari(大多数情况下是移动的)完全忽略了这些设置
我将尝试进行黑客攻击并强制safari mobile刷新,但这不是我所期望的

我想知道我是否可以:

  • 在不向用户显示存在任何问题的情况下处理异常(对用户完全透明)
  • 通过替换防伪令牌用户名来防止此问题,如果我的浏览器缓存相关攻击在下一版本的浏览器中停止工作,该用户名将允许用户再次登录,而不会出现此异常
  • 我真的不想依赖于浏览器行为,因为每个浏览器的行为都不同
更新1

为了澄清一下,我知道如何处理MVC中的错误。问题是,这种错误处理根本不能解决我的问题。错误处理的基本思想是重定向到带有漂亮消息的自定义错误页面。但我想防止这个错误发生,而不是以用户可见的方式处理它。我所说的句柄是指抓取用户名替换或其他合适的操作,然后继续登录

更新2


我已经添加了以下对我有效的解决方案。

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

[HandleError(View="AntiForgeryExceptionView", ExceptionType = typeof(HttpAntiForgeryException))]
Todo所以请确保在web.config中打开自定义错误

<customErrors mode="On"/>

您还可以查看此文件以了解有关句柄错误的更多信息


编辑既然您使用的是MVC4,而博客是关于MVC3的,您也可以查看一下,但版本应该不会有什么不同。

经过一段时间的调查,我想我找到了一些方法,可以为用户消除这个错误。它并不完美,但至少不显示错误页面:

我根据
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
    }
该解决方案的主要思想是将防伪异常重定向到主索引操作。如果用户仍然未经身份验证,则会显示登录页面;如果用户已通过身份验证,则会显示索引页面

更新1
这个解决方案有一个潜在的问题。如果有人使用不同的凭据登录,则在出现错误时应添加额外的登录运行时-注销以前的用户并登录新用户。这种情况不会得到处理。

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

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

一个老问题-但我今天遇到了这个问题,我解决这个问题的方法是重定向到注销操作,如下所示:

public ActionResult Login(string returnUrl) 
{
    if (WebSecurity.IsAuthenticated)
        return RedirectToAction("LogOff");

    ...
}

是的,但这说明了重定向(因此处理此错误会中断当前操作(执行)。我希望在不中断操作的情况下处理此错误,因此在本例中,处理、替换用户名并使用正确的数据继续登录。我认为,当您捕获到错误时,可以将其重定向到视图(控制器)在这里,您可以用以前输入的数据替换用户名并继续登录。另请参见:这对我来说非常有效。我不需要它来做任何幻想。只是不要抛出黄色屏幕。谢谢,这似乎非常有效,并且仍然提供相同的安全性。这对我不起作用,它会给出完全相同的错误,但在这一行:System.Web.Helpers.antifforgery.Validate();@AmrElgarhy没错,现在你可以抓住它了!
public ActionResult Login(string returnUrl) 
{
    if (WebSecurity.IsAuthenticated)
        return RedirectToAction("LogOff");

    ...
}