【问题标题】:FormsAuthentication cookie not persistentFormsAuthentication cookie 不持久
【发布时间】:2012-07-01 06:01:37
【问题描述】:

我正在尝试使用以下代码(在 AccountController.cs 中)将 FormsAuthenticationTicket 保存到 cookie:

FormsAuthenticationTicket ticket = new FormsAuthenticationTicket
          (1, user.UserEmail, DateTime.Now, 
           DateTime.Now.AddMinutes(FormsAuthentication.Timeout.TotalMinutes), 
           false, null);

string encTicket = FormsAuthentication.Encrypt(ticket);
HttpCookie faCookie = new HttpCookie(FormsAuthentication.FormsCookieName,
ticket.ToString());
HttpContext.Response.Cookies.Add(faCookie);

if (Url.IsLocalUrl(returnUrl) && returnUrl.Length > 1 && returnUrl.StartsWith("/")
           && !returnUrl.StartsWith("//") && !returnUrl.StartsWith("/\\"))
           {
             return Redirect(returnUrl);
           }
           else
          {
             return RedirectToAction("Index", "Home");
          }

当我单步调试调试器时,一切似乎都很好。直到我到达Application_AuthenticateRequest,在那里我尝试检索 cookie:

HttpCookie authCookie = Request.Cookies[FormsAuthentication.FormsCookieName];

        if (authCookie != null)
        {
         //do stuff here
        }

当我查看 Cookies 集合时,那里什么都没有。我可以在 AccountController 代码中添加另一个普通 cookie,它显示得很好。无论我是否包含 UserData,问题仍然存在,所以我认为这不是大小问题。

感谢您提供的任何见解。

【问题讨论】:

    标签: asp.net-mvc-3 cookies formsauthenticationticket


    【解决方案1】:

    cookie 的最大大小为 4096 字节。如果超过此值,cookie 将不会被保存。

    使用以下方法检查 Cookie 大小:

    int cookieSize = System.Text.UTF8Encoding.UTF8.GetByteCount(faCookie.Values.ToString());
    

    【讨论】:

      【解决方案2】:

      您正在将 cookie 添加到响应中。完成此操作后,请确保您已立即重定向。只有在随后的请求中,您才能希望从Request.Cookies 集合中读取它。

      【讨论】:

      • 感谢您的建议。我其实是在重定向,之后常规cookie可用,ticket不可用。
      【解决方案3】:

      虽然您的身份验证票证设置为持久性并具有过期日期,但实际的 cookie 没有。

      在创建 cookie 时添加类似的内容:

      var faCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encTicket)
                         {
                             Expires = ticket.Expiration
                         };
      

      【讨论】:

      • 拯救了我的一天@Ted Nyberg!
      【解决方案4】:

      在编写 cookie 的代码中,不能将 null 传递给带有加密 cookie 的 userData 参数。 IsPersistent 为 false 很好。

      FormsAuthenticationTicket ticket = new FormsAuthenticationTicket
                (1, user.UserEmail, DateTime.Now, 
                 DateTime.Now.AddMinutes(FormsAuthentication.Timeout.TotalMinutes), 
                 false, null);
      

      在下面做这样的事情: 在我的示例中,您可以将 userData.ToString() 替换为空字符串。只是不要给它一个空值!这应该可以解决您的问题。

       FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(
                  1,                             // version
                  userId.UserEmail,                      // a unique value that identifies the user
                  DateTime.Now,                  // created
                  DateTime.Now.AddMinutes(FormsAuthentication.Timeout.TotalMinutes),  // expires
                  false,                    // persistent?
                  userData.ToString(),   // user specific data (optional) //NOTE:  DO NOT pass NULL as encrypted string value will become NULL (argh)
                  FormsAuthentication.FormsCookiePath  // the path for the cookie
                  );
      

      然后在你的 global.asax.cs 您将在 FormsAuthentication_OnAuthenticate 事件中检查该 cookie 您的代码在此处会有所不同,因为我已经编写了自定义表单身份验证并且使用的是 userId 而不是电子邮件,就像您的情况一样。

      请注意以下逻辑,如果您在编写 auth cookie 时为 UserData 参数传递 null,则会失败。

          if (authCookie == null || authCookie.Value == "")
          {
              return;
          }
      

      这是 globalasax.cs 文件中的完整事件:

      protected void FormsAuthentication_OnAuthenticate(Object sender, FormsAuthenticationEventArgs e)
      {
          //STEP #1 of Authentication/Authorization flow
          //Reference:  http://msdn.microsoft.com/en-us/library/ff649337.aspx
          //==================================================================
          if (FormsAuthentication.CookiesSupported == true)
          {
      
              //Look for an existing authorization cookie when challenged via [Authorize]
              HttpCookie authCookie = Context.Request.Cookies[FormsAuthentication.FormsCookieName];
              if (authCookie == null || authCookie.Value == "")
              {
                  return;
              }
              FormsAuthenticationTicket authTicket = null;
              try
              {
                  //Reading from the ticket
                  authTicket = FormsAuthentication.Decrypt(authCookie.Value);
                  //Check the Cookiename (which in this case is UserId).  If it is null, then we have an issue
                  if (authTicket.Name == null)
                  {
                      FormsAuthentication.SignOut();
                      authCookie.Value = null;
                  }
      
              }
              catch (Exception ex)
              {
                  //Unable to decrypt the auth ticket
                  return;
              }
      
              //get userId from ticket
              string userId = authTicket.Name;
      
      
              Context.User = new GenericPrincipal(
                        new System.Security.Principal.GenericIdentity(userId, "MyCustomAuthTypeName"), authTicket.UserData.Split(','));
      
              //We are officially 'authenticated' at this point but not neccessarily 'authorized'
          }
          else
          {
              throw new HttpException("Cookieless Forms Authentication is not supported for this application.");
      
          }
      }
      

      【讨论】:

      • 您好,非常感谢您,我遇到了类似的问题,我根据您的回答解决了它。我的代码完全没问题,只是我将FormsAuthenticationTicket 设置为持久性,因此唯一的原因是无法正常工作。如果您知道,请解释为什么会发生这种情况?谢谢!
      【解决方案5】:

      您在创建 FormsAuthenticationTicket 时将 isPersistent 参数设置为 false。此参数应设置为 true。

      【讨论】:

        猜你喜欢
        • 2011-12-02
        • 1970-01-01
        • 1970-01-01
        • 2010-10-02
        • 2011-08-18
        • 1970-01-01
        • 2012-04-14
        • 2014-02-05
        • 1970-01-01
        相关资源
        最近更新 更多