Keeping user logged in - FormsAuthentication

2019-02-24 08:00发布

问题:

I am having the hardest time figuring this out. I am using FormAuthentication. When a user logs in and they check remember me, I want to the user to stay logged in for 24 hours. The problem is, no matter what I do the user is automatically logged out after like 30 minutes. We the user selected remember me, I set a persistent cookie to expire 24 hours later. I can see the cookie in the browser options and the expiration is correct. If I leave the site and go back in say an hour. The user is logged out...... He is some code snippets of what I have.

bool IsValid = Membership.ValidateUser(LoginControl.UserName, LoginControl.Password);

if (IsValid)
{
    e.Authenticated = true;

    if (LoginControl.RememberMeSet)
    {
        FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket(LoginControl.UserName, true, 1440); // 1 day
        string encryptedTicket = FormsAuthentication.Encrypt(authTicket);
        HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
        cookie.Expires = authTicket.Expiration;
        HttpContext.Current.Response.Cookies.Set(cookie);
        Response.Redirect(FormsAuthentication.GetRedirectUrl(LoginControl.UserName, true), true);
        FormsAuthentication.SetAuthCookie(LoginControl.UserName, true);
        FormsAuthentication.RedirectFromLoginPage(LoginControl.UserName, true);
    }
    else
    {
        FormsAuthentication.SetAuthCookie(LoginControl.UserName, false);
        FormsAuthentication.RedirectFromLoginPage(LoginControl.UserName, false);
    }
}

Here is my web.config

<authentication mode="Forms">
  <forms loginUrl="~/Account/Login.aspx" defaultUrl="/" timeout="1" cookieless="UseCookies"  protection="All" slidingExpiration="true" ticketCompatibilityMode="Framework40"/>
</authentication>

When a user does not check remember me, I set a non-persistent cookie and after 1 minute of inactivity the user logs out. This is working correctly. The problem is when a remember cookie is set and the user returns the user is not logged in anymore even though a cookie is there.

回答1:

Set the following session state time out in web.config. By default, session timeout is 20 minutes.

<system.web>
   ...
   <authentication mode="Forms">
      <forms loginUrl="~/Account/Login.aspx" timeout="1440" />
   </authentication>
   ...  
   <sessionState timeout="1440"/>
   ...
</system.web>

Solution

Set authentication cookie using default ticket setting if user checks remember me. Otherwise, create AuthenticationTicket by yourself.

string username = LoginControl.UserName;

if (LoginControl.RememberMeSet)
{
    FormsAuthentication.SetAuthCookie(username, true);
    FormsAuthentication.RedirectFromLoginPage(username, true);
}
else
{
    var authTicket = new FormsAuthenticationTicket(username, true, 1);
    string encryptedTicket = FormsAuthentication.Encrypt(authTicket);

    var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, 
        encryptedTicket)
    {
        HttpOnly = true,
        Secure = FormsAuthentication.RequireSSL,
        Path = FormsAuthentication.FormsCookiePath,
        Domain = FormsAuthentication.CookieDomain,
        Expires = authTicket.Expiration
    };
    Response.Cookies.Set(cookie);

    // ***** Here is the fix *****
    // Do not use FormsAuthentication.SetAuthCookie or RedirectFromLoginPage
    // if you create own FormsAuthenticationTicket.
    Response.Redirect("~/default.aspx");
}

Testing

protected void Page_Load(object sender, EventArgs e)
{
    if (User.Identity.IsAuthenticated)
    {
        var sb = new StringBuilder();
        var id = (FormsIdentity) User.Identity;
        var ticket = id.Ticket;
        sb.Append("Authenticated");
        sb.Append("<br/>CookiePath: " + ticket.CookiePath);
        sb.Append("<br/>Expiration: " + ticket.Expiration);
        sb.Append("<br/>Expired: " + ticket.Expired);
        sb.Append("<br/>IsPersistent: " + ticket.IsPersistent);
        sb.Append("<br/>IssueDate: " + ticket.IssueDate);
        sb.Append("<br/>Name: " + ticket.Name);
        sb.Append("<br/>UserData: " + ticket.UserData);
        sb.Append("<br/>Version: " + ticket.Version);
        Label1.Text = sb.ToString();
    }
    else
        Label1.Text = "Not Authenticated";
}

To be honest with you, Session and Authentication Cookie time out 1 minute is too low, but it is up to you.

In addition, please a note in web.config that you create AuthenticationTicket yourself. Next person who debug your code will definitely appreciate it.

Problem (Updated)

If we create FormsAuthenticationTicket ourself, we should not use FormsAuthentication.RedirectFromLoginPage which will override our custom expire date and uses the one from web.config.