"返回"按钮和防伪令牌

时间:2014-06-24 00:57:44

标签: asp.net-mvc razor

我得到一个Runtime error相关的防伪属性。

执行以下步骤:

  1. 创建MVC Web应用程序并启动
  2. 注册 joe@acme.org
  3. 退出
  4. 注册 jane@acme.org
  5. 退出
  6. joe@acme.org
  7. 登录
  8. 点击后退按钮
  9. jane@acme.org
  10. 登录

    错误: The provided anti-forgery token was meant for a different claims-based user than the current user.

    可以采取哪些措施来防止此错误发生?

4 个答案:

答案 0 :(得分:32)

我刚才遇到了同样的问题,并通过禁用登录视图的缓存来解决它。它实际上很有意义,并且不需要代码或异常处理。

我的登录控制器方法现在看起来像这样:

[AllowAnonymous]
[OutputCache(NoStore = true, Location = OutputCacheLocation.None)]
public ActionResult LogOn(Uri returnUrl)

当禁用缓存并且用户单击浏览器上的后退按钮时,会向服务器发出新请求,并再次传递页面,并将防伪签名设置为正确的用户。

我认为这是解决问题的一种更清洁,更简单和合理的方法。

答案 1 :(得分:23)

这是忽略错误并将用户返回登录屏幕的一种方法。这只是一个例子。

创建一个名为HandleAntiforgeryTokenErrorAttribute的新类,该类继承自HandleErrorAttribute。覆盖OnException方法。

public class HandleAntiforgeryTokenErrorAttribute : HandleErrorAttribute
{
    public override void OnException(ExceptionContext filterContext)
    {
        filterContext.ExceptionHandled = true;
        filterContext.Result = new RedirectToRouteResult(
            new RouteValueDictionary(new { action = "Login", controller = "Account" }));
    }
}

转到FilterConfig班级并将该属性注册为全局过滤器。

public class FilterConfig
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new HandleErrorAttribute());
        filters.Add(new HandleAntiforgeryTokenErrorAttribute()
            { ExceptionType = typeof(HttpAntiForgeryException) }
        );
    }
}

答案 2 :(得分:3)

接受的答案只捕获所有异常,因为它不像原始HandleErrorAttribute那样通过异常类型过滤它们。

使用以下代码仅处理HttpAntiForgeryException:

public static class FilterConfig
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new HandleErrorAttribute());
        filters.Add(new HandleAntiforgeryTokenErrorAttribute());
    }
}

public class HandleAntiforgeryTokenErrorAttribute : HandleErrorAttribute
{
    public HandleAntiforgeryTokenErrorAttribute()
    {
        ExceptionType = typeof(HttpAntiForgeryException);
    }

    public override void OnException(ExceptionContext filterContext)
    {
        if (!ExceptionType.IsInstanceOfType(filterContext.Exception))
        {
            return;
        }

        filterContext.ExceptionHandled = true;
        filterContext.Result =
            new RedirectToRouteResult(
                new RouteValueDictionary(
                    new {
                            area = string.Empty,
                            action = "Index",
                            controller = "Home"
                        }));

    }
}

答案 3 :(得分:0)

缓存的旧页面,通过后退按钮恢复生机,包含旧的防伪标记并导致异常。 Rowan Freeman的全局过滤器解决方案重定向到登录页面。但是,此缓存问题还会导致站点使用旧令牌提供旧登录页面。提交表单将导致相同的异常。 Ergo,IMO,两种解决方案(Rowan Freeman和julealgon)都应该实施。

理论上,避免每个页面的缓存也应该起到作用,但成本很高(延迟,带宽)。我选择重新路由到登录,以便能够使用缓存并避免在登录时缓存以缓解异常,即实现两者。