Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When attempt logoff, The provided anti-forgery token was meant for user "XXXX", but the current user is ""

Tags:

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.

like image 386
crichavin Avatar asked May 07 '13 01:05

crichavin


2 Answers

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.

like image 161
cem Avatar answered Sep 28 '22 01:09

cem


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";
        }
    }
});
like image 41
Javier Avatar answered Sep 28 '22 01:09

Javier