10

我正在使用 MVC 3,从我所看到的一切都正确设置。

用户 Authenticates 提交带有 AntiForgery 令牌的表单,一切正常。

除非用户将要提交的表单保持打开状态并且在该时间内用户登录已过期。

当用户提交表单时,他们不再经过身份验证,他们应该被带回登录页面。(这确实发生过几次)

相反,异常“未提供所需的防伪令牌或无效。” 被抛出。我想它被抛出是因为加密的令牌包含一些无法验证的用户详细信息,因为用户不再经过身份验证。

异常是正确的,但不应该被抛出,因为页面应该跳回登录屏幕,因为真正的问题是用户离开打开的表单并且他的登录超时。

这个问题很难复制,因为它并不总是这样做。

我看到很多人似乎有这个问题,但没有解决方案即将到来。

这是 MVC 本身的问题吗?

机器密钥设置和东西都是正确的,所以这不是问题。

4

3 回答 3

5

造成这种情况的原因似乎是在某些大型组织中,人们在很长一段时间内让他们的机器打开而不重新启动,并且浏览器打开而不关闭它们。有时甚至连续数周。

如果稍后添加或更改了机器密钥,则未关闭或关闭浏览器的机器是导致此错误的机器。一旦每台机器重新启动或浏览器关闭,错误就会停止。

注意:要停止此错误,创建机器密钥也很重要。

谷歌:机器密钥生成器

于 2012-07-12T14:26:04.363 回答
4

我在这里添加了一个更好的答案,因为这太痛苦了,而且整个网络上的答案都很糟糕,我想我会添加我目前工作的解决方案。

从根本上说(忽略各种选项),AntiForgeryToken 的工作原理是添加一个会话 cookie,然后在表单发布时通过使用 [ValidateAntiForgeryToken] 属性装饰控制器来读取该 cookie。

首先,在我们作为一般规则进行任何修复之前,请始终执行以下操作。

  1. 在 web.config 中创建一个 machineKey,如下所示。

    <machineKey validationKey="YOUR_KEY" decryptionKey="YOUR_KEY" validation="SHA1" decryption="AES" />

    ** 注意 SHA1,这已经不是很安全了,但那是另一个讨论 **

    谷歌<machineKey> Generator和配置。

    http://msdn.microsoft.com/en-us/library/w8h3skw9%28v=vs.100%29.aspx

  2. 将默认 cookie 名称从“__RequestVerificationToken”更改为不会被其他应用程序使用的名称。(我总是使用 GUID)。

    这样做AntiForgeryConfig.CookieName = "YOUR_NAME";

  3. 创建一个新的自定义属性。

此错误似乎无缘无故出现的原因是 cookie 仅在会话的生命周期内有效。由于各种原因,但主要是人们在非常非常非常长的时间内打开页面,会话超时。因为会话已超时,cookie 不再有效。

另一个问题是,如果您在发布到控制器上具有 [Authorize] 属性,则事物流将在检查谁经过身份验证之前触发 HttpAntiForgeryException。(在大多数基于 cookie 的身份验证中,当会话过期时,用户不再经过身份验证)

解决这个问题的方法是创建一个自定义的 [CustomValidateAntiForgeryToken] 属性。

[AttributeUsage( AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = false, Inherited = true )]
  public class CustomValidateAntiForgeryToken : FilterAttribute, IAuthorizationFilter {

    public void OnAuthorization( AuthorizationContext filterContext ) {

      if ( filterContext == null ) {
        throw new ArgumentNullException( "filterContext" );
      }

      try {
        AntiForgery.Validate();
      }
      catch {

        // Here do whatever is you wish 
        // you could just re throw the error or what ever.

        // In this case I have redirected to a Signout

        filterContext.Result = new RedirectToRouteResult( 
          new RouteValueDictionary( 
            new {
              action     = "Sign_Out",
              controller = "SOME_CONTROLLER",
              area       = ""
            } 
          )
        );

      }

    }

  }

最后,如果您在任何当前运行的系统中更改任何内容,请确保每个人都注销,关闭他们的浏览器,甚至在可能的情况下重新启动,并清除他们的 cookie 和缓存。即使在更改代码之后,您仍然可能会收到错误,直到您为每个用户完成此操作。

显然,人们有完全不同的需求,但希望这能提供足够的建议来控制这个非常常见和烦人的问题。

如果有人看到任何可以帮助或可以添加的内容,请执行。

于 2014-04-12T23:23:06.530 回答
1

在您的操作上,将属性放在[Authorize]属性之上[ValidateAntiForgeryToken]。他们从上到下按顺序执行。因此,它应该点击授权并看到您不再经过身份验证。

于 2011-12-21T15:54:40.050 回答