In this tutorial we will examine how to validate a user's credentials against the Membership user store using both programmatic means and the Login control. We will also look at how to customize the login control's appearance and behavior.
Introduction In the preceding tutorial we looked at how to create a new user account in the Membership framework.
We first looked at programmatically creating user accounts via the Membership class's CreateUser method, and then examined using the CreateUserWizard Web control.
However, the login page currently validates the supplied credentials against a hard-coded list of username and password pairs. We need to update the login page's logic so that it validates credentials against the Membership framework's user store. Much like with creating user accounts, credentials can be validated programmatically or declaratively. The Membership API includes a method for programmatically validating a user's credentials against the user store.
NET ships with the Login Web control, which renders a user interface with textboxes for the username and password and a button to log in. Validating Credentials Against the Membership User Store For web sites that use forms authentication, a user logs on to the website by visiting a login page and entering their credentials.
These credentials are then compared against the user store. If they are valid, then the user is granted a forms authentication ticket, which is a security token that indicates the identity and authenticity of the visitor.
To validate a user against the Membership framework, use the Membership class's ValidateUser method. The ValidateUser method takes in two input parameters - username and password - and returns a Boolean value indicating whether the credentials were valid.
Like with the CreateUser method we examined in the previous tutorial, the ValidateUser method delegates the actual validation to the configured Membership provider. Recall that the SqlMembershipProvider stores users' passwords using one of three formats: For encrypted or hashed passwords, the SqlMembershipProvider transforms the password value passed into the ValidateUser method into its equivalent encrypted or hashed state and then compares it with what was returned from the database.
If the password stored in the database matches the formatted password entered by the user, the credentials are valid. We created this login page back in the An Overview of Forms Authentication tutorial, creating an interface with two TextBoxes for the username and password, a Remember Me checkbox, and a Login button see Figure 1. In the Forms Authentication Configuration and Advanced Topics tutorial we updated the login page's code to store additional information in the forms authentication ticket's UserData property.
The Login Page's Interface Includes Two TextBoxes, a CheckBoxList, and a Button Click to view full-size image The login page's user interface can remain unchanged, but we need to replace the Login button's Click event handler with code that validates the user against the Membership framework user store. Update the event handler so that its code appears as follows: We start by calling the Membership. ValidateUser method, passing in the supplied username and password.
If that method returns true, then the user is signed into the site via the FormsAuthentication class's RedirectFromLoginPage method. RedirectFromLoginPage creates the forms authentication ticket and then redirects the user to the appropriate page. If the credentials are invalid, however, the InvalidCredentialsMessage Label is displayed, informing the user that their username or password was incorrect. That's all there is to it! To test that the login page works as expected, attempt to login with one of the user accounts you created in the preceding tutorial.
Note When the user enters her credentials and submits the login page form, the credentials, including her password, are transmitted over the Internet to the web server in plain text.
That means any hacker sniffing the network traffic can see the username and password. This will ensure that the credentials as well as the entire page's HTML markup are encrypted from the moment they leave the browser until they are received by the web server.
If the credentials are valid, the HTTP response includes the authentication ticket in a cookie. Therefore, a hacker attempting to break into your site could create a program that exhaustively sends HTTP requests to the login page with a valid username and a guess at the password. Through brute force, such a program might be able to stumble upon a user's password, especially if the password is weak. To prevent such brute force attacks, the Membership framework locks out a user if there are a certain number of unsuccessful login attempts within a certain period of time.
The exact parameters are configurable through the following two Membership provider configuration settings: The default value is 5. The default value is If a user has been locked out, she cannot login until an administrator unlocks her account. When a user is locked out, the ValidateUser method will always return false, even if valid credentials are supplied. While this behavior lessens the likelihood that a hacker will break into your site through brute force methods, it can end up locking out a valid user who has simply forgotten her password or accidentally has the Caps Lock on or is having a bad typing day.
Unfortunately, there is no built-in tool for unlocking a user account. We will examine creating administrative interfaces for accomplishing common user account- and role-related tasks in a future tutorial. Note One downside of the ValidateUser method is that when the supplied credentials are invalid, it does not provide any explanation as to why. In Step 4 we will see how to show a more detailed message to the user when their login attempt fails.
Moreover, the Login control automatically signs in the user assuming the submitted credentials are valid , thereby saving us from having to write any code. Start by removing the existing markup and code in Login. You may delete it outright, or simply comment it out. You can enter these delimiters manually, or, as Figure 2 shows, you may select the text to comment out and then click the Comment out the selected lines icon in the Toolbar.
Similarly, you can use the Comment out the selected lines icon to comment out the selected code in the code-behind class. At this point your screen should look similar to Figure 3. When the Login control's Log In button is clicked, a postback will occur and the Login control will call the Membership. ValidateUser method, passing in the entered username and password.
If the credentials are invalid, the Login control displays a message stating such. If, however, the credentials are valid, then the Login control creates the forms authentication ticket and redirects the user to the appropriate page.
The Login control uses four factors to determine the appropriate page to redirect the user to upon a successful login: Whether the Login control is on the login page as defined by loginUrl setting in the forms authentication configuration; this setting's default value is Login. Add a Login Control to the Page Click to view full-size image Take a moment to test out the Login control by visiting the site through a browser and logging in as an existing user in the Membership framework.
The Login control's rendered interface is highly configurable. There are a number of properties that influence its appearance; what's more, the Login control can be converted into a template for precise control over the layout the user interface elements. The remainder of this step examines how to customize the appearance and layout. The appearances of these elements are all configurable through the Login control's numerous properties. Furthermore, additional user interface elements - such as a link to a page to create a new user account - can be added by setting a property or two.
Let's spend a few moments to gussy up the appearance of our Login control. Therefore, clear out the TitleText property value in order to remove the Login control's title. Let's change the User Name: Label to read Username:. The Remember me next time CheckBox's Text property can be set through the Login control's RememberMeText property , and its default checked state is configurable through the RememberMeSet property which defaults to False.
The Login control offers two properties for adjusting the layout of its user interface controls. The TextLayout property indicates whether the Username: Labels appear to the left of their corresponding TextBoxes the default , or above them. The Orientation property indicates whether the username and password inputs are situated vertically one above the other or horizontally. I am going to leave these two properties set to their defaults, but I encourage you to try setting these two properties to their non-default values to see the resulting effect.
Note In the next section, Configuring the Login Control's Layout, we will look at using templates to define the precise layout of the Layout control's user interface elements. This adds a hyperlink to the Login control's interface pointing to the page we created in the preceding tutorial. After making these property changes, your Login control's declarative markup and appearance should look similar to that shown in Figure 5.
But what if we need finer control over the rendered output? Or what if our application requires additional credentials for authentication? Many financial websites, for instance, require users to supply not only a username and password, but also a Personal Identification Number PIN , or other identifying information.
Whatever the reasons may be, it is possible to convert the Login control into a template, from which we can explicitly define the interface's declarative markup. We need to do two things in order to update the Login control to collect additional credentials: Update the Login control's interface to include Web control s to collect the additional credentials.
Override the Login control's internal authentication logic so that a user is only authenticated if their username and password is valid and their additional credentials are valid, too.
To accomplish the first task, we need to convert the Login control into a template and add the necessary Web controls. As for the second task, the Login control's authentication logic can be superseded by creating an event handler for the control's Authenticate event.
Let's update the Login control so that it prompts users for their username, password, and email address and only authenticates the user if the email address supplied matches their email address on file. We first need to convert the Login control's interface to a template. From the Login control's Smart Tag, choose the Convert to template option.
Converting the Login control to a template adds a LayoutTemplate to the control's declarative markup with HTML elements and Web controls defining the user interface. As Figure 7 shows, converting the control to a template removes a number of properties from the Properties window, such as TitleText, CreateUserUrl, and so forth, since these property values are ignored when using a template. Likewise, feel free to add any new Web controls to the template.
However, it is important that Login control's core Web controls remain in the template and keep their assigned ID values. To collect the visitor's email address, we need to add a TextBox to the template. As Figure 8 shows, the Login control's user interface now includes a third textbox. ValidateUser method to validate the supplied credentials. Correspondingly, the value entered into the Email TextBox has no bearing on whether the user can log in. In Step 3 we will look at how to override the Login control's authentication logic so that the credentials are only considered valid if the username and password are valid and the supplied email address matches up with the email address on file.
Modifying the Login Control's Authentication Logic When a visitor supplies her credentials and clicks the Log In button, a postback ensues and the Login control progresses through its authentication workflow.