При попытке выхода из системы, предоставленный токен анти-подделки предназначен для пользователя "XXXX", но текущий пользователь ""

У меня есть приложение MVC 4 и возникают проблемы, когда сеанс форм заканчивается, а затем пользователь пытается выйти из системы.

Ex. таймаут установлен на 5 мин. Пользователь входит в систему. Пользователь ничего не делает в течение 10 минут. Пользователь нажимает на ссылку LogOff. Пользователь получает ошибку: "Предоставленный токен анти-подделки предназначен для пользователя" XXXX ", но текущий пользователь" ".

Затем пользователю пришлось пройти через какую-то гимнастику, чтобы обойти это, чтобы они могли снова войти в систему, а затем снова выйти из системы (выход из системы закрывается на время).

Я думаю, я понимаю, почему это происходит... но не уверен, как это исправить.

EDIT: Почему я думаю, что это происходит потому, что изначально, когда страница загружается, токен AntiForgery создается для текущего пользователя. Но тогда, когда сессия истекает, и они пытаются перейти на страницу выхода из системы, текущий пользователь "вместо" фактического пользователя. Таким образом, существует несоответствие и ошибка отображается.

Ответ 1

На самом деле вы можете обрабатывать его с помощью IExceptionFilter, который будет перенаправлен на /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() 
{
}

Также вы можете использовать [HandleError(ExceptionType=typeof(HttpAntiForgeryException)...], но для этого требуется customErrors On.

Ответ 2

Ответ @cem был действительно полезен для меня, и я добавил небольшое изменение, чтобы включить сценарий аякс-вызовов с antiforgerytoken и истекшим сеансом.

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;
    }
}

... и на стороне клиента вы можете добавить глобальный обработчик ошибок ajax для перенаправления на экран входа...

$.ajaxSetup({
    error: function (x) {
        if (x.status === 403) {
            window.location = "/Account/Login";
        }
    }
});