如何解决:所提供的防伪令牌是针对不同基于声明的用户而非当前用户的。

12

我遇到了这个错误:

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

我不确定该如何纠正这个问题。

我有一个MVC5网站,其中包括一个登录页面。

以下是发生在此页面上的情况:

  1. 用户AAA登录。(没有问题)
  2. 我尝试访问用户无权访问的视图。
    • 我已将类装饰为Authorize(Roles="aa")。
  3. 然后该视图会注销用户并将其返回到登录页面。
  4. 用户AAA登录。(这次我收到了上述错误)

需要注意的是:
我正在使用customErrors,这就是我看到错误消息的地方。

当我登出用户时,我运行此方法:

[HttpGet]
public void SignOut()
{
    IAuthenticationManager authenticationManager = HttpContext.GetOwinContext().Authentication;
    authenticationManager.SignOut(MyAuthentication.ApplicationCookie);
}

在登出时我可能漏掉了什么吗?

更新:
这只发生在上面提到的步骤#2。
如果我登录,然后退出(调用相同的代码),然后重新登录,那么我就不会遇到这个问题。


尝试添加 [ValidateAntiForgeryToken] 属性。 - Balaji Marimuthu
我在我的Post方法中有这个,当用户登录时。[HttpPost] [AllowAnonymous] [ValidateAntiForgeryToken] - John Doe
5个回答

12

我认为您忽略了发布相关代码。您拥有的Signout操作返回void。如果直接在浏览器中访问此操作,则用户在注销后会得到一个空页面,没有任何进一步操作的方式。因此,我只能假设您要么通过AJAX调用它,要么从另一个操作中作为方法进行调用。

MVC中防伪造工作的方式是在用户的计算机上设置包含唯一生成令牌的cookie。如果用户已登录,则使用其用户名来组成该令牌。为了设置一个没有用户名的新cookie,必须先注销用户并发生新请求以设置新cookie。如果仅仅将用户注销而不进行重定向或其他操作,那么新的无用户cookie还未设置。然后,在用户提交请求时,旧的基于用户的cookie被发送回来,而MVC正在寻找新的无用户cookie,就出现了异常。

就像我说的那样,您没有发布足够的代码以确定出现问题的原因和位置,但简单来说,确保在注销用户后进行新请求,这样可以设置新的cookie。


谢谢您的解释。在这种情况下,我没有进行重定向,这导致了我的问题。但是,我仍然注意到一个问题,当授权属性失败时,它会重定向到登录页面,但我不确定它是如何实现的。(它没有触发我的断点) - John Doe
我不太确定你具体在说什么。AuthorizeAttribute 的默认行为是重定向到在 Web.config(ASP.NET Membership)或身份启动配置文件(ASP.NET Identity)中定义的 URL。它实际上并没有注销用户,而且你可以技术上将他们带到任何页面。标准做法是使用登录,这样用户就有机会实际登录或使用其他具有访问权限的帐户进行身份验证。 - Chris Pratt
我还在学习MVC,但在学习的过程中,我不知何故会默认记录用户退出行为。然而,当授权失败时,它重复了这种行为(记录了但未重定向)。我创建了一个自定义授权,以便我可以处理这个问题,它看起来很有效。 - John Doe

1

我能够重现这个问题,只需要在下一个视图加载之前点击登录按钮多次即可。为了防止错误,我在第一次点击后禁用了登录按钮。

<button type="submit" onclick="this.disabled=true;this.form.submit();"/>

1
如果出现网络问题,导致服务器触发的重定向无法返回给用户,这将以对用户不友好的方式失败。他们在您的服务器上被注销,没有错误提示;但是据他们所知,注销失败了,并且由于按钮被禁用,他们无法再次尝试。 - Dan Is Fiddling By Firelight

0

禁用防伪验证执行的身份验证检查。将以下内容添加到您的Application_Start方法中:

AntiForgeryConfig.SuppressIdentityHeuristicChecks = true。


当我添加了那行代码后,出现了错误:提供的防伪标记是为用户“AAA”而设计的,但当前用户为空。 - John Doe
不知道,但我的代码是可以工作的。在你的操作中尝试使用以下代码:[OutputCache(NoStore=true, Duration = 0, VaryByParam= "None")] - Balaji Marimuthu
AntiForgeryConfig自动完成没有给我选择“SuppressIdentityHeuristicChecks”的选项。我正在使用Asp .NET Web API。 - DevEng
1
应该包括“在设置此值时要小心。不正确使用可能会在应用程序中打开安全漏洞。”的注释。来源:https://learn.microsoft.com/en-us/previous-versions/aspnet/web-frameworks/jj158419(v=vs.111) - d219

0

尝试:

public ActionResult Login(string modelState = null)
{
    if (modelState != null)
        ModelState.AddModelError("", modelState);

    return View();
}
[ValidateAntiForgeryToken]
public async Task<ActionResult> Login(LoginViewModel model)
{
    AuthenticationManager.SignOut();

    return RedirectToAction("Login", "Controller", new { modelState = "MSG_USER_NOT_CONFIRMED" });
}

-2

我有类似的问题。我在我的项目中找到了这个文本 "@Html.AntiForgeryToken() ",并且一个地方将会在“视图文件”Views - test.cshtml中。

    @using (Html.BeginForm())
    @Html.AntiForgeryToken()
    <div class="form-horizontal">
        <div class="form-group">
            @if (@Model.interviewed)
...

我删除了这行代码("@Html.AntiForgeryToken()"),现在运行良好。

PS:但是我没有在文件_LoginPartial.cshtml中删除此代码。 祝你好运!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接