【问题标题】:Anti-Forgery Token was meant for a different claims-based userAnti-Forgery Token 适用于不同的基于声明的用户
【发布时间】:2016-03-25 16:53:19
【问题描述】:

我正在使用 ASP.NET 身份登录的应用程序中开发注销功能。我可以成功登录,但是当我注销然后尝试再次登录时,我收到以下消息:

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

这是我的注销代码:

 public ActionResult Logout()
        {
            SignInManager.Logout();
            return View("Index"); 
        }

**SignInManager.cs**
 public void Logout()
        {
            AuthenticationManager.SignOut(); 
        }

用户按下注销按钮后,他将被带到登录屏幕。网址仍然显示“http://localhost:8544/Login/Logout”。因为我们在登录屏幕上,所以它应该只说“http://localhost:8544/Login”。

【问题讨论】:

  • 我认为您可以在注销操作中使用重定向使其工作,而不是直接返回视图。 return RedirectToAction("Index"); 这有望正确设置所有标头和 cookie 信息。
  • 就我而言,这是 EDMX 文件的一些问题。一旦我更新了所有表格,问题就消失了。

标签: asp.net asp.net-mvc


【解决方案1】:

对我有用的是切换使用的中间件的顺序。首先添加app.UseAuthentication(),然后添加防伪材料。我就是这样做的:

app.UseAuthentication();
app.Use(next => ctx =>
        {
            var tokens = antiforgery.GetAndStoreTokens(ctx);

            ctx.Response.Cookies.Append("XSRF-TOKEN", tokens.RequestToken,
                new CookieOptions() { HttpOnly = false });

            return next(ctx);
});

反之,则会创建一个不适用于经过身份验证的用户的令牌。

【讨论】:

  • 这解决了我的 .net 核心身份问题。真让人抓狂。
  • 谢谢!这个序列的东西解决了我的 Asp.Net Core 2.1 问题
  • 谢谢,它成功了。解决了这个问题,节省了很多时间。
  • 是的,工作了,但花了一天的时间之后却没有!
【解决方案2】:

我发现用户在通过身份验证后提交登录页面时遇到了这个问题。我通过以下方式复制了此错误:

  1. 登录时打开两个标签,
  2. 从一个注销,
  3. 重新加载两者,
  4. 登录到一个,
  5. 尝试与其他人登录。在进入 POST: /Account/Login 操作之前发生错误。

我的大多数用户在移动设备上使用网络应用程序,因此他们在登录页面添加书签并在后台打开标签页时将其拉出并提交是有道理的。我也推测有时他们会在登录表单中加载一个休眠选项卡,然后将其拉起并提交。

我意识到有很多方法可以解决这个问题。我通过两个更改解决了这个问题:

  1. 我在“GET: /Account/Login”操作中添加了对 User.Identity.IsAuthenticated 的检查:
if (User.Identity.IsAuthenticated)
{
   try
   {
      return RedirectToLocal(returnUrl);
   }
   catch
   {
      return RedirectToAction("index", "Home");
   }
}
  1. 在我的控制器中,我创建了一个“检查是否登录”操作:
[AllowAnonymous]
public JsonResult CheckLogedIn()
{
    try
    {
        return Json(new { logged_in = User.Identity.IsAuthenticated }, JsonRequestBehavior.AllowGet);
    }
    catch
    {
        return Json(new { logged_in = false }, JsonRequestBehavior.AllowGet);
    }
}

我在视图中反复调用它以在已经登录时将所有打开的登录表单重定向到登录页面之外:

<script type="text/javascript">
    setInterval(function () {
        $.ajax({
                url: '@Url.Action("CheckLogedIn", "Account")',
                type: "GET",
            }).done(function (data) {
                if (data.logged_in) {
                    window.location = '/';
                }
            });
    }, 5000);  
</script>

这对我来说效果很好。希望它可以帮助你。

【讨论】:

  • 感谢您的解释!我在我们的日志中不时看到这个错误,但还无法重现它。感谢您的回答,我现在可以这样做 - 并且可能会修复该错误:-)
【解决方案3】:

我在登录时遇到同样的错误很长时间了,但一直无法找出原因。终于我找到了,所以我把它贴在这里(虽然它的原因略有不同)以防其他人拥有它。

这是我的代码:

//
// GET: /login
[OutputCache(NoStore = true, Location = System.Web.UI.OutputCacheLocation.None)]
public ActionResult Login()
{
    return View();
}

//
// POST: /login
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
    AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie);

    if (!ModelState.IsValid)
    {
        return View(model);
    }
    //etc...

这对于 99.99% 的登录来说都很好,但是我时不时地遇到上述错误,尽管直到现在我都无法重现它。

该错误仅在有人快速连续两次单击登录按钮时发生。但是,如果我删除了 Login 操作中的 AuthenticationManager.SignOut 行,那就没问题了。我不知道为什么我把那条线放在那里,但它会导致问题 - 删除它可以解决问题。

【讨论】:

    【解决方案4】:

    您返回的是View,而不是调用RedirectToAction()。所以发生的事情是视图在注销请求的上下文中运行,用户仍然登录。在请求完成之前他们不会被注销。

    所以,试试

    public ActionResult Logout()
    {
        SignInManager.Logout();
        return RedirectToAction("Index", "Home");
    }
    

    【讨论】:

      【解决方案5】:

      试试这个:

      public ActionResult Logout()
      {
          AuthenticationManager.SignOut();
          Session.Abandon();
          return RedirectToAction("Index");
      }
      

      这将重新加载您的登录页面,该页面将为您提供一个新的 CSRF 令牌。

      【讨论】:

      • asp.net 身份验证未以任何方式链接到会话 :)
      • @blowdart 是的,但根据应用程序,清除会话变量可能是有意义的,特别是如果与该用户的会话相关联,同时用户已注销。
      【解决方案6】:

      试试这个:

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

      【讨论】:

      • 欢迎来到 Stack Overflow!请不要只用源代码回答。尝试对您的解决方案如何工作提供一个很好的描述。见:How do I write a good answer?。谢谢
      【解决方案7】:

      我的登录方法中没有 Sean 提到的 AuthenticationManager.SignOut 命令。在加载下一个视图之前,我可以通过多次单击登录按钮来重现。第一次单击后我禁用了登录按钮以防止出现错误。

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

      【讨论】:

        猜你喜欢
        • 2017-12-02
        • 1970-01-01
        • 2011-07-02
        • 2018-01-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-08-01
        相关资源
        最近更新 更多