未提供所需的防伪标记或无效

Wil*_*eys 9 c# model-view-controller asp.net-mvc antiforgerytoken

我正在使用MVC 3,从我能看到的一切设置正确.

用户Authenticates使用AntiForgery Token提交表单,一切正常.

除非用户已将表单保留为打开并且在该时间内用户登录已过期,否则这是除非.

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

取而代之的是"未提供所需的防伪令牌或无效".被扔了.我想它被抛出是因为加密的令牌包含一些用户细节,由于用户不再经过身份验证而无法验证.

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

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

我看到很多人似乎遇到了这个问题,但没有解决方案.

这是MVC本身的问题吗?

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

Wil*_*eys 5

这样做的原因似乎是,在某些大型组织中,人们在没有重新启动的情况下打开他们的计算机并打开浏览器而不会在很长时间内关闭它们.有时甚至几周.

如果稍后添加了机器密钥或更改了机器密钥,则尚未关闭或关闭浏览器的计算机将导致此错误.重新启动每台计算机或关闭浏览器后,错误将停止.

注意:要停止此错误,创建计算机密钥也很重要.

谷歌:机器密钥生成器

  • 我不知道为什么这个被投了票.这正是造成我们问题的原因,一旦添加了机器密钥并且所有机器都重新启动,问题就不再发生了. (4认同)

Wil*_*eys 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       = ""
            } 
          )
        );

      }

    }

  }
Run Code Online (Sandbox Code Playgroud)

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

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

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