如何解决我的ASP.Net MVC应用程序iisreset后发生的AntiForgeryTokenexception?

我在ASP.Net MVC中的AntiForgeryToken有问题。 如果我在我的web服务器上执行iisreset,并且用户继续他们的会话,他们会跳转到login页面。 这并不可怕,但是AntiForgery令牌爆炸了,唯一的办法就是在浏览器上吹走cookie。

有了版本1的testing版本,它在我读取cookie的时候会出错,所以我在请求validation令牌之前先擦除它,但是当它被释放的时候它就被修复了。

现在我想我会回滚到我的代码,修复testing版的问题,但我不禁想到我错过了一些东西。 有一个更简单的解决scheme,赫克我应该放弃他们的帮手,并从头创build一个新的? 我感觉到很多问题都是因为它和旧的ASP.Netpipe道很紧密地联系在一起,并且试图把它搞糊涂做一些没有真正devise的东西。

我看了一下ASP.Net MVC 2 RC的源代码,看起来代码没有太大变化,但是我没有尝试过,我不认为这里有任何答案。

这是exception堆栈跟踪的相关部分。

编辑:我只是意识到我没有提到,这只是试图插入令牌的GET请求。 这不是在你开始POST时发生的validation。

System.Web.Mvc.HttpAntiForgeryException: A required anti-forgery token was not supplied or was invalid. ---> System.Web.HttpException: Validation of viewstate MAC failed. If this application is hosted by a Web Farm or cluster, ensure that <machineKey> configuration specifies the same validationKey and validation algorithm. AutoGenerate cannot be used in a cluster. ---> System.Web.UI.ViewStateException: Invalid viewstate. Client IP: 127.0.0.1 Port: 4991 User-Agent: scrubbed ViewState: scrubbed Referer: blah Path: /oursite/Account/Login ---> System.Security.Cryptography.CryptographicException: Padding is invalid and cannot be removed. at System.Security.Cryptography.RijndaelManagedTransform.DecryptData(Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount, Byte[]& outputBuffer, Int32 outputOffset, PaddingMode paddingMode, Boolean fLast) at System.Security.Cryptography.RijndaelManagedTransform.TransformFinalBlock(Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount) at System.Security.Cryptography.CryptoStream.FlushFinalBlock() at System.Web.Configuration.MachineKeySection.EncryptOrDecryptData(Boolean fEncrypt, Byte[] buf, Byte[] modifier, Int32 start, Int32 length, IVType ivType, Boolean useValidationSymAlgo) at System.Web.UI.ObjectStateFormatter.Deserialize(String inputString) --- End of inner exception stack trace --- --- End of inner exception stack trace --- at System.Web.UI.ViewStateException.ThrowError(Exception inner, String persistedState, String errorPageMessage, Boolean macValidationError) at System.Web.UI.ViewStateException.ThrowMacValidationError(Exception inner, String persistedState) at System.Web.UI.ObjectStateFormatter.Deserialize(String inputString) at System.Web.UI.ObjectStateFormatter.System.Web.UI.IStateFormatter.Deserialize(String serializedState) at System.Web.Mvc.AntiForgeryDataSerializer.Deserialize(String serializedToken) --- End of inner exception stack trace --- at System.Web.Mvc.AntiForgeryDataSerializer.Deserialize(String serializedToken) at System.Web.Mvc.HtmlHelper.GetAntiForgeryTokenAndSetCookie(String salt, String domain, String path) at System.Web.Mvc.HtmlHelper.AntiForgeryToken(String salt, String domain, String path) 

如果您的MachineKey设置为AutoGenerate,那么validation令牌等将无法在应用程序重新启动时生效 – ASP.NET将在启动时生成一个新密钥,然后将无法正确解密令牌。

如果你看到这很多,我会build议:

  1. configuration一个静态的MachineKey(你应该可以在应用程序级执行此操作),请参阅“如何configurationMachineKey”以获取更多信息
  2. 尝试不使用站点时正在执行IIS复位1

1要做到这一点的最好方法是通过一个负载均衡的应用程序,这将需要您设置一个静态MachineKey。 另一种方法是通过在网站的根目录下放置一个名为app_offline.htm的文件来closures网站,这会使网站脱机并显示您的消息 – 至less用户会期望出现问题。

现在我已经用了一个解决scheme来抛弃cookie,如果抛出exception。 如果再次抛出exception,我会让它发生。

我不会把这个标记为“现在”的答案,希望有人有更好的答案。

 public static class MyAntiForgeryExtensions { // Methods public static string MyAntiForgeryToken(this HtmlHelper helper) { return MyAntiForgeryToken(helper, null); } public static string MyAntiForgeryToken(this HtmlHelper helper, string salt) { string fragment; string path = helper.ViewContext.HttpContext.Request.ApplicationPath; try { fragment = helper.AntiForgeryToken(salt, null, path); } catch (HttpAntiForgeryException) { // okay, scrub the cookie and have another go. string cookieName = GetAntiForgeryTokenName(path); helper.ViewContext.HttpContext.Request.Cookies.Remove(cookieName); fragment = helper.AntiForgeryToken(salt, null, path); } return fragment; } #region AntiForgeryData code that shouldn't be sealed // Copied from AntiForgeryData since they aren't accessible. internal static string GetAntiForgeryTokenName(string appPath) { if (String.IsNullOrEmpty(appPath)) { return "__RequestVerificationToken"; } else { return "__RequestVerificationToken_" + Base64EncodeForCookieName(appPath); } } private static string Base64EncodeForCookieName(string s) { byte[] rawBytes = Encoding.UTF8.GetBytes(s); string base64String = Convert.ToBase64String(rawBytes); // replace base64-specific characters with characters that are safe for a cookie name return base64String.Replace('+', '.').Replace('/', '-').Replace('=', '_'); } #endregion } 

我有这个问题,并修复你需要做的是添加一个明确的机器密钥在您的networkingconfiguration…

 <machineKey validationKey="D82960E6B6E9B9029D4CAB2F597B5B4AF631E3C182670855D25FBDE1BFAFE19EFDE92ABBD1020FC1B2AE455D5B5F8D094325597CE1A7F8B15173407199C85A16" decryptionKey="577404C3A13F154908D7A5649EEC8D7C8A92C35A25A3EC078B426BB09D426A71" validation="SHA1" decryption="AES" /> 

确保将其置于web.config中…

 <system.web> 

您可以添加AntiForgeryConfig.SuppressIdentityHeuristicChecks = true; 进入global.asax

 protected void Application_Start() { AntiForgeryConfig.SuppressIdentityHeuristicChecks = true; } 

如果我在我的web服务器上执行iisreset,并且用户继续他们的会话,他们会跳转到login页面。

iisreset没有理由把用户带到login页面。 如果您使用cookie来跟踪身份validation信息并拥有无状态应用程序,则即使服务器重新启动(当然,如果在重置期间发出请求,将会失败),用户仍应该保持身份validation状态。

其实我发现这在我的login行动中工作:

  public ActionResult LogOn() { formsAuthentication.SignOut(); Response.Cookies.Clear(); Session[SessionKeys.USER_SESSION_KEY] = null; Session.Clear(); Session.Abandon(); return View(); } 

重要的部分是:Response.Cookies.Clear();