Как устранить исключение AntiForgeryToken, которое возникает после iisreset в моем приложении ASP.Net MVC?
У меня проблемы с AntiForgeryToken в ASP.Net MVC. Если я выполняю iisreset на своем веб-сервере, и пользователь продолжает сеанс, он переходит на страницу входа. Не страшно, но токен AntiForgery взорвется, и единственный способ возобновить работу - удалить куки в браузере.
В бета-версии версии 1 при чтении cookie-файлов у меня возникали ошибки, поэтому я обычно чистил его, прежде чем запрашивать токен проверки, но это было исправлено, когда он был выпущен.
Сейчас я думаю, что вернусь к своему коду, который исправил проблему с бета-версией, но я не могу не думать, что что-то упустил. Есть ли более простое решение, черт возьми, я должен просто бросить их помощник и создать новый с нуля? У меня возникает ощущение, что большая часть проблемы заключается в том, что он так глубоко привязан к старому конвейеру ASP.Net и пытается заставить его сделать что-то, для чего он не был предназначен.
Я посмотрел исходный код ASP.Net MVC 2 RC, и похоже, что код сильно не изменился, поэтому, хотя я и не пробовал, я не думаю, что там есть какие-либо ответы.
Вот соответствующая часть трассировки стека исключения.
Изменить: я только что понял, что я не упомянул, что это просто пытается вставить токен в запрос GET. Это не проверка, которая происходит, когда вы запускаете POST.
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)
6 ответов
Если для вашего MachineKey установлено значение AutoGenerate, то ваши токены проверки и т. Д. Не сохранятся после перезапуска приложения - ASP.NET сгенерирует новый ключ при запуске и не сможет правильно расшифровать токены.
Если вы часто это видите, я бы предложил:
- Настройка статического MachineKey (вы должны быть в состоянии сделать это на уровне приложения), см. "Как: настроить MachineKey" для получения дополнительной информации.
- Старайтесь не выполнять сброс IIS, когда сайт используется1
1 Лучший способ сделать это - использовать приложение с балансировкой нагрузки, которое потребует от вас установки статического MachineKey. Другой вариант - отключить сайт, поместив файл с именем app_offline.htm
в корне сайта, который переведет сайт в автономный режим и отобразит ваше сообщение - по крайней мере, пользователи будут ожидать, что что-то пойдет не так.
На данный момент я выбрал решение, которое очищает куки, если выбрасывается исключение. Если исключение будет выдано снова, я просто позволю этому случиться так, как было.
Я не буду помечать это как "ответ" пока в надежде, что у кого-то есть лучший ответ.
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
}
У меня была эта проблема, и чтобы исправить то, что вам нужно сделать, это добавить явный ключ компьютера в веб-конфигурации...
<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;
}
Если я выполняю iisreset на своем веб-сервере, и пользователь продолжает сеанс, он переходит на страницу входа.
Нет причин, по которым iisreset может привести пользователя на страницу входа. Если вы используете куки для отслеживания информации об аутентификации и имеете приложение без сохранения состояния, пользователь должен оставаться аутентифицированным даже после перезагрузки сервера (конечно, если во время сброса будет сделан запрос, он потерпит неудачу).
На самом деле я обнаружил, что это работает в моем действии входа в систему:
public ActionResult LogOn()
{
formsAuthentication.SignOut();
Response.Cookies.Clear();
Session[SessionKeys.USER_SESSION_KEY] = null;
Session.Clear();
Session.Abandon();
return View();
}
Важной частью было: Response.Cookies.Clear();