Making user login persistant with ASP .Net Membership

20,796

Solution 1

I finally figured out the last piece of the puzzle. When the app pool of my server was being recycled (configured by the hosting provider), the viewstate encryption key was being auto-re-generated. This meant that even though the cookies were valid & non expired (pre-return visit), when the user returned the encyrption had changed, and the cookie was no longer valid.

The solution was to manually specify a static validation key. The following link can be used to generate the neccessary web.config tag for this.

http://www.aspnetresources.com/tools/keycreator.aspx

UPDATE:

Here's a more configurable site to generate Machine Key

Source Tree - Generage attribute

I realize that this might have a minor security impact, I guess theoritically it's safer to have a changing key in case your key gets brute forced and compromises any data you might be storing in the view state, but you probably shouldn't be storing sensitive information in the viewstate as it's not inherently safe anyway.

Example:

<configuration>
  <system.web>
    <machineKey
        validationKey="97CEB2D3DEBF853649EAB851F56F08BA328423F935C97244CF5300925B6FF7D2C43084C73CBAF19D5193755EF7F87A3FFC714675F9197C822BAEEC97E853B91E"
        decryptionKey="A72F69A4650348E3AA249A8179516D67C8553B3D4BD165B9"
        validation="SHA1" />
  </system.web>
</configuration>

Solution 2

I think you'd be better-off using the FormsAuthentication.SetAuthCookie method rather than writing a lot of code yourself.

I believe your membership provider settings in the web.config may be conflicting with the settings you're providing in code, plus you're not providing a cookie name.

Try the following:

if (Membership.ValidateUser(userName, password))
{
    FormsAuthentication.SetAuthCookie(userName, true); //Creates a cookie named "XXXAuth" - see settings in web.config below
}

In conjunction with the following settings in web.config:

<authentication mode="Forms">
    <forms cookieless="UseCookies" loginUrl="~/SignIn.aspx" name="XXXAuth" slidingExpiration="true" timeout="432000"/>
</authentication>


<membership defaultProvider="XXXMembershipProvider">
    <providers>
        <clear />
        <add name="XXXMembershipProvider" type="System.Web.Security.SqlMembershipProvider" applicationName="XXX" connectionStringName="XXX" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" requiresUniqueEmail="true" minRequiredPasswordLength="5" minRequiredNonalphanumericCharacters="0" passwordFormat="Hashed" maxInvalidPasswordAttempts="5" passwordAttemptWindow="10" passwordStrengthRegularExpression=""/>
    </providers>
</membership>

Simply change the "timeout" value in the authentication block to be a longer value if you really want to create an indefinite log-in period. I believe 432000 = 5 days.

If you want your users to be able to explicitly log-out, simply call the following method in response to a button click (or whatever):

FormsAuthentication.SignOut();

Hope this helps.

Solution 3

Reading your code you might have accidently set the FormsAuthenticationTicket timeout value to zero. The line in your code where you create the ticket reads: -

Dim authTicket As FormsAuthenticationTicket = New FormsAuthenticationTicket(Username, True, Expiration.Subtract(Expiration).TotalMinutes)

The value of Expiration.Subtract(Expiration).TotalMinutes will always be "0".

You may be better using the longhand format for creating the ticket as follows which would result in less ambiguity.

Public Shared Sub AuthenticateUser(ByVal Username As String)
    Dim Expiration As DateTime = DateTime.Now.AddMonths(3)
    Dim userData As String = String.Empty

    Dim authTicket As FormsAuthenticationTicket = _
       New FormsAuthenticationTicket( _
         Username, _
         DateTime.Now, _
         Expiration, _
         true, _
         userData, _
         FormsAuthentication.FormsCookiePath)
    Dim EncryptedTicket As String = FormsAuthentication.Encrypt(authTicket)
    Dim AuthCookie As New HttpCookie(FormsAuthentication.FormsCookieName, EncryptedTicket)
    AuthCookie.Expires = Expiration
    HttpContext.Current.Response.Cookies.Add(AuthCookie)
End Sub

There is also a good Microsoft KB article here on "Understanding the Forms Authentication Ticket and Cookie"

.

Share:
20,796
Tom Halladay
Author by

Tom Halladay

Live, breathe, and eat web development

Updated on July 05, 2022

Comments

  • Tom Halladay
    Tom Halladay almost 2 years

    I have a website that is built in ASP.NET 3.5 & SQL Server 2005, using the sql membership provider, and presumably forms authentication.

    Since security needs on my site are very low, I would like to authenticate once, and then keep the log in persisted indefinitely (without giving the user the choice).

    What is happening is that the user logs in, stays logged in for the session, and then the next time they arrive, they are logged out.

    How can I get the log-in persisted?

    Here's the technical details, I have experimented with many variations of durations.

     Try
                If Membership.ValidateUser(UserName.Text, Password.Text) Then
                    Security.UserManager.AuthenticateUser(UserName.Text)
    
                    If FormsAuthentication.GetRedirectUrl(UserName.Text, False) = "/default.aspx" Then
                        Try
                            'Custom Logic'
                        Catch Ex As Exception
                            'Custom Error handling'
                        End Try
                    Else
                        FormsAuthentication.RedirectFromLoginPage(UserName.Text, True)
                    End If
                End If
            Catch ex As Exception
                RaiseEvent ExceptionThrown(New ApplicationException("An error occurred trying to log the user in after account creation.", ex))
            End Try
    
    Public Shared Sub AuthenticateUser(ByVal Username As String)
        Dim Expiration As DateTime = DateTime.Now.AddMonths(3)
    
        Dim authTicket As FormsAuthenticationTicket = New FormsAuthenticationTicket(Username, True, Expiration.Subtract(Expiration).TotalMinutes)
        Dim EncryptedTicket As String = FormsAuthentication.Encrypt(authTicket)
        Dim AuthCookie As New HttpCookie(FormsAuthentication.FormsCookieName, EncryptedTicket)
        AuthCookie.Expires = Expiration
        HttpContext.Current.Response.Cookies.Add(AuthCookie)
    End Sub
    

    Web Config:

    <membership defaultProvider="SqlProvider" userIsOnlineTimeWindow="15">
       <providers>
          <clear />
          <add
             name="SqlProvider"
             type="System.Web.Security.SqlMembershipProvider"
             connectionStringName="GlobalConnString"
             applicationName="/"
             enablePasswordRetrieval="false"
             enablePasswordReset="true"
             requiresQuestionAndAnswer="false"
             requiresUniqueEmail="true"
             passwordFormat="Hashed"
             minRequiredPasswordLength="5"
             minRequiredNonalphanumericCharacters="0"
          />
       </providers>
    </membership>
    
    
    <authentication mode="Forms">
        <forms timeout="1439200" name="SITENAME" loginUrl="/login.aspx" />
    </authentication>
    

    Edit: Here is the cookie information that is getting stored by the client:

    Name    ASP.NET_SessionId
    Value   r4dz1555f1pdne45n1zrlkmg
    Host    SITEADDRESS.com
    Path    /
    Secure  No
    Expires At End Of Session
    
    Name    .ASPXAUTH
    Value   648767AC72A60DBA49650A361A2FA446BA992F792055EF5B488CADC95DF495315C1C577F1C8E67E67BD937A7AB6CC5DAED85D8D64E4ED7867FC0FC395F48FED7FB631033CE441DE85223E8B3EBAE616C
    Host    www.SITEADDRESS.com
    Path    /
    Secure  No
    Expires Tue, 09 Jun 2009 17:51:31 GMT
    
    Name    ASP.NET_SessionId
    Value   gn5pcymhfsnua455yp45wpej
    Host    www.SITEADDRESS.com
    Path    /
    Secure  No
    Expires At End Of Session
    
    Name    SITENAME
    Value   9610E8515F3DBC088DAC286E1F44311A20CB2BBB57C97F906F49BC878A6C6AC0B9011777402AEA130DCDC521EF4FBB3393DB310083F72EB502AE971183306C24F07F696B3695C67DD73166F1653DF52B
    Host    www.SITEADDRESS.com
    Path    /
    Secure  No
    Expires Tue, 20 Dec 2011 06:14:10 GMT