Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Keeping user logged in - FormsAuthentication

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.

like image 369
Michael Brown Avatar asked May 03 '13 17:05

Michael Brown


People also ask

Why is form authentication not sufficient anymore?

Forms authentication does not encrypt the user's credentials. Therefore, forms authentication is not secure unless used with SSL.

What is the difference between logic controls and forms authentication?

What is the difference between login controls and Forms authentication? Forms authentication can be easily implemented using login controls without writing any code. Login control performs functions like prompting for user credentials, validating them and issuing authentication just as the FormsAuthentication class.

How does form authentication work?

A client requests access to a protected resource. If the client is unauthenticated, the server redirects the client to a login page. The client submits the login form to the server. The server attempts to authenticate the user.


1 Answers

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.

like image 81
Win Avatar answered Oct 10 '22 14:10

Win