我遇到了一个与防伪属性相关的运行时错误
。
请按以下步骤进行操作:
- 创建一个MVC Web应用程序并启动它
- 注册 joe@acme.org
- 退出登录
- 注册jane@acme.org
- 退出登录
- 以joe@acme.org的身份登录
- 点击返回按钮
- 以jane@acme.org的身份登录
错误:提供的防伪令牌是针对与当前用户不同的基于声明的用户。
如何避免发生这种错误?
我遇到了一个与防伪属性相关的运行时错误
。
请按以下步骤进行操作:
错误:提供的防伪令牌是针对与当前用户不同的基于声明的用户。
如何避免发生这种错误?
我刚遇到了同样的问题,通过禁用登录视图的缓存来解决。这实际上很有道理,而且不需要编写代码或异常处理。
我的登录控制器方法现在看起来像这样:
[AllowAnonymous]
[OutputCache(NoStore = true, Location = OutputCacheLocation.None)]
public ActionResult LogOn(Uri returnUrl)
当缓存被禁用时,如果用户在浏览器上单击后退按钮,则会向服务器发出新请求并再次传递页面,并且防伪令牌将设置为正确的用户。
我认为这是解决问题的一种更加清洁、简单和合乎逻辑的方法。
这是一种忽略错误并将用户返回到登录屏幕的方法。这只是一个例子。
创建一个名为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) }
);
}
}
HandleAntiforgeryTokenErrorAttribute
类中设置 ExceptionType = typeof(HttpAntiForgeryException)
,那会更好,因为这是它的目的。 - Enrique Carro已接受的答案仅捕获所有异常,因为它不像原始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"
}));
}
}
缓存的旧页面会在使用“返回”按钮时重新启用,其中包含旧的防伪标记,这会导致异常。Rowan Freeman 的全局过滤器解决方案会将用户重定向到登录页面。 然而,这个缓存问题还会导致站点提供一个带有旧令牌的旧登录页面。 提交表单将导致相同的异常。 因此,在我看来,应该实施 Rowan Freeman 和 julealgon 的两种解决方案。
理论上,对于每个页面避免缓存也可以解决问题,但代价显著(延迟,带宽)。我选择重新路由到登录界面以便能够使用缓存并避免在登录界面上进行缓存以减轻异常,即同时实现两者。