所提供的防伪标记是针对用户“{user}”的,但当前用户为空。

3
我在表单提交后遇到了防伪标记问题。我一直收到这个错误消息:
“提供的防伪标记是为用户“{user}”准备的,但当前用户为空”
与其他人提出的问题不同的是,我的问题是它说当前用户为空,而防伪标记正在寻找一个用户。这毫无意义,因为当我检查HttpContext.Current.User.Identity.Name和Membership.GetUser().UserName时,它们确实拥有防伪标记正在寻找的用户。这真的没有任何意义。
NewRecordEntry.cshtml
<h2>New Record</h2>
@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()
    <div id="new-record-entry">
        @Html.DropDownListFor(model => model.recordTypeID, Model.GetRecordTypeList())
    </div>

    <input type="submit" name="NewRecordEntry" id="continue" size="11" />
}

控制器

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult NewRecordEntry(FormCollection frm, NewRecordEntryViewModel nrevm)
    {
        TempData["NewRecordEntry"] = nrevm;
        return RedirectToAction("NewRecord", "FakeController");
    }    

身份验证过滤器

public class FakeAuthenticationFilter : ActionFilterAttribute, IAuthenticationFilter
{
    public void OnAuthentication(AuthenticationContext filterContext)
    {
        // Get userData stored in a session. Workplace environment does not allow cookies
        UserData userData = (UserData) filterContext.HttpContext.Session[UserInfo.SessionUser];
        if (userData != null)
        {
            // Get identity and principal
            var identity = new GenericIdentity(UserInfo.SessionUser, "Forms");
            var principal = new FakePrincipal(identity);

            principal.UserData = userData;

            // Set the context user.
            HttpContext.Current.User = principal;
        }
        else
        {
            filterContext.Result = new RedirectResult("~/Login");
        }
    }

    public void OnAuthenticationChallenge(AuthenticationChallengeContext filterContext)
    {
    }
  }

会员资格

public class FakeMembershipProvider : MembershipProvider
{
    public override bool ValidateUser(string username, string password)
    {
        // Check if this is a valid user.
        // The application sends the username and password to an LDAP DLL which
        //   reurns "Success" if it was a match.
        string result = LoginService.AuthenticateUser(username, password);
        if (result == "Success")
        {
             return true;
        }
        return false;
    }

    public override MembershipUser GetUser(string username, bool userIsOnline)
    {

        if (LoginService.UserData != null)
        {
            return new MembershipUser("FakeMembershipProvider", 
                username, LoginService.UserData.UserID,
                null, null, null, true, false,
                DateTime.MinValue, DateTime.MinValue, DateTime.MinValue, 
                DateTime.MinValue, DateTime.MinValue);
        }
        return null;
    }
}

登录提交控制器

#region Login Post Controllers
    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Login(FormCollection frm, LoginViewModel lvm, string returnUrl)
    {
        List<string> errorList = null;
        try
        {

            if (ModelState.IsValid)
            {
                string result = Services.ValidateLogin(lvm);

                if (result == "Success")
                {
                    if (Url.IsLocalUrl(returnUrl)
                        && returnUrl.Length > 1
                        && returnUrl.StartsWith("/")
                        && !returnUrl.StartsWith("//")
                        && !returnUrl.StartsWith("/\\"))
                    {
                        return base.Redirect(returnUrl);
                    }
                    return base.RedirectToAction("Index");
                }
                else
                {
                    TempData["errors"] = result;
                    ModelState.AddModelError("", result);
                }
            }
            else
            {
                errorList = Services.AddErrorMesagesToView(ModelState);
                TempData["errors"] = errorList;
            }
            //return base.RedirectToAction("Admin", new { section = section });
            ModelState.Clear();
            return View(new LoginViewModel());
        }
        catch (NullReferenceException ne)
        {
            if (ne.Source != null)
                Console.WriteLine("NullReferenceException source: {0}", ne.Source);
        }
        catch (HttpException he)
        {
            if (he.Source != null)
                Console.WriteLine("HttpException source: {0}", he.Source);
        }
        catch (Exception e)
        {
            if (e.Source != null)
                Console.WriteLine("Exception source: {0}", e.Source);
        }
        finally
        {
            ModelState.Clear();
        }

        return base.RedirectToAction("Login");
    }
    #endregion

验证登录

    public static string ValidateLogin(LoginViewModel lvm)
    {
        /* string ldapServer = WebConfigurationManager.AppSettings["LDAPServer"];
        string result = Fakeauthenticate.Fakeauth.LdapAuth(lvm.Login, lvm.Password, ldapServer);
         */
        string result = null;
        const int INACTIVE = 1;

        FakeEntities db = new FakeEntities();

        // This is the only feasible way to call an SQL user-defined scalar function
        string sqlQuery = "SELECT [dbo].[Util_GetUserActivationStatus] ({0})";
        Object[] parameters = { lvm.Login };
        int status = db.Database.SqlQuery<int>(sqlQuery, parameters).FirstOrDefault();

        if (status == INACTIVE)
        {
            return "The user is currently locked out.";
        }

        if (Membership.ValidateUser(lvm.Login, lvm.Password))
        {
            HttpContext.Current.Session[UserInfo.SessionUser] = LoginBusiness.GetUserData(lvm.Login);
            HttpContext.Current.Session.Timeout = UserInfo.Timeout;

            result = "Success";
        }
        else
        {
            result = LoginBusiness.AuthenticateUser(lvm.Login, lvm.Password);
            if (result == "Login_Failure")
            {
                if (HttpContext.Current.Session[lvm.Login] == null)
                {
                    HttpContext.Current.Session[lvm.Login] = 1;
                }
                else
                {
                    uint loginFailures = (uint)HttpContext.Current.Session[lvm.Login];
                    HttpContext.Current.Session[lvm.Login] = ++loginFailures;

                    // If the maximum number of login failures have been reached, then lock the user out.
                    if ((uint)HttpContext.Current.Session[lvm.Login] == UserInfo.MAX_LOGIN_FAILURES)
                    {
                        db.Util_LockUserOut(lvm.Login);
                        return "Your account has been temporarily locked.";
                    }
                }
            }
        }

        return result;
    }

显示代码的哪一部分? - Andy Narain
好的,我添加了一些代码。 - Andy Narain
这一行是问题所在 HttpContext.Current.User = principal; 如果你把它移除,程序会正常运行。但是,我不确定为什么或者有什么好的解决方案。我目前将 Thread.Current 设置为 principal,但这并不总是有效。 - Mrchief
谢谢,但是我已经解决了。 - Andy Narain
我不记得了。我需要再看一下我的代码,然后回复你。 - Andy Narain
显示剩余7条评论
2个回答

1

您应该检查表单中是否有多个@Html.AntiForgeryToken()。如果是,则删除所有除一个之外的内容。

还要确保您没有提交表单两次。这会导致AntiForgeryToken出现问题。

如果想要禁用此检查,请将以下内容添加到您的Application_Start方法中:

AntiForgeryConfig.SuppressIdentityHeuristicChecks = true

这基本上是唯一的方法吗? - Andy Narain
这要看情况。你在哪里使用这个防伪标记? - Mihai Dinculescu
基本上,当我要创建一个新记录时,第一个网页会要求输入记录类型。这是一个表单。之后,根据类型,进入新记录的表单页面。顺便说一句,我尝试了你建议的方法,但仍然没有成功。 - Andy Narain
你的表单里有两个 @Html.AntiForgeryToken() 吗? - Mihai Dinculescu
我不这么认为。我只需要点击一次提交按钮。让我跟踪问题,看看程序是否提交了两次。我希望我有15。 - Andy Narain
显示剩余12条评论

0
问题出在您的FakeAuthenticationFilter上。我猜测您正在使用此过滤器加载页面的控制器操作。FakeAuthenticationFilter设置HttpContext.Current.User = new FakePrincipal(identity)。这个主体可能有一个Name属性,这就是您在错误消息中看到的用户。.NET使用此主体在页面上生成令牌,但当您提交令牌时,HttpContext将没有相同的主体。
解决方案可能是将FakeAuthenticationFilter放在您的NewRecordEntry操作上。

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