I’m having problems with the AntiForgeryToken in ASP.Net MVC. If I do an iisreset on my web server and a user continues with their session they get bounced to a login page.
i had this issue and to fix what you need to do is add an explicit machine key in your web-config...
<machineKey validationKey="D82960E6B6E9B9029D4CAB2F597B5B4AF631E3C182670855D25FBDE1BFAFE19EFDE92ABBD1020FC1B2AE455D5B5F8D094325597CE1A7F8B15173407199C85A16" decryptionKey="577404C3A13F154908D7A5649EEC8D7C8A92C35A25A3EC078B426BB09D426A71" validation="SHA1" decryption="AES" />
ensure its placed in web.config within...
<system.web>
You can add AntiForgeryConfig.SuppressIdentityHeuristicChecks = true;
into global.asax
protected void Application_Start() {
AntiForgeryConfig.SuppressIdentityHeuristicChecks = true;
}
If I do an iisreset on my web server and a user continues with their session they get bounced to a login page.
There's no reason an iisreset to bring the user to the login page. If you use cookies to track authentication information and have a stateless application, the user should stay authenticated even after a server reboot (of course if a request is made during the reset it will fail).
For now I've gone with a solution that scrubs the cookie if the exception is thrown. If the exception is thrown again I'll just let it happen as it was.
I won't mark this as 'the' answer for now in the hope that someone has a better answer.
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
}
Actually I found this to work in my logon action:
public ActionResult LogOn()
{
formsAuthentication.SignOut();
Response.Cookies.Clear();
Session[SessionKeys.USER_SESSION_KEY] = null;
Session.Clear();
Session.Abandon();
return View();
}
The important part was : Response.Cookies.Clear();
If your MachineKey is set to AutoGenerate, then your verification tokens, etc won't survive an application restart - ASP.NET will generate a new key when it starts up, and then won't be able to decrypt the tokens correctly.
If you are seeing this a lot, I'd suggest:
1 The best way to do this is by having a loadbalanced application, which will require you to set a static MachineKey. Another option is to take the site down by placing a file named app_offline.htm
in the root of the site, which will take the site offline and display your message - at least the users will expect things to go wrong.