I have an MVC 4 app and having issues when the forms session expires and then the user tries to logoff.
Ex. timeout is set to 5 min. User logs in. User does nothing for 10 min. User clicks the LogOff link. User gets error: "The provided anti-forgery token was meant for user "XXXX", but the current user is ""."
The user then had to go through some gymnastics to get around this so they can re-login then re-logout (logout is being used to close their timecard for the day).
I think I understand why this happens...but not sure how to fix it.
EDIT: Why I think this is happening is because originally when the page is loaded, the AntiForgery token is generated for the currently logged in user. But then when the session expires and they try to navigate to the logoff page, the current user is "" instead of the actual user. As such there is a mismatch and the error is rendered.
Actually you can handle it with IExceptionFilter
, that will redirect to the /Account/Login
public class HandleAntiForgeryError : ActionFilterAttribute, IExceptionFilter
{
#region IExceptionFilter Members
public void OnException(ExceptionContext filterContext)
{
var exception = filterContext.Exception as HttpAntiForgeryException;
if (exception != null)
{
var routeValues = new RouteValueDictionary();
routeValues["controller"] = "Account";
routeValues["action"] = "Login";
filterContext.Result = new RedirectToRouteResult(routeValues);
filterContext.ExceptionHandled = true;
}
}
#endregion
}
[HandleAntiForgeryError]
[ValidateAntiForgeryToken]
public ActionResult LogOff()
{
}
Also you can use [HandleError(ExceptionType=typeof(HttpAntiForgeryException)...]
but it requires customErrors On.
The answer of @cem was really helpful for me and I added a small change to include the scenario of ajax calls with antiforgerytoken and expired session.
public void OnException(ExceptionContext filterContext)
{
var exception = filterContext.Exception as HttpAntiForgeryException;
if (exception == null) return;
if (filterContext.HttpContext.Request.IsAjaxRequest())
{
filterContext.HttpContext.Response.StatusCode = 403;
filterContext.ExceptionHandled = true;
}
else
{
var routeValues = new RouteValueDictionary
{
["controller"] = "Account",
["action"] = "Login"
};
filterContext.Result = new RedirectToRouteResult(routeValues);
filterContext.ExceptionHandled = true;
}
}
... and on the client side you can add a global ajax error handler to redirect to the login screen...
$.ajaxSetup({
error: function (x) {
if (x.status === 403) {
window.location = "/Account/Login";
}
}
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With