AspAlliance.com LogoASPAlliance: Articles, reviews, and samples for .NET Developers
URL:
http://aspalliance.com/articleViewer.aspx?aId=2045&pId=-1
Creating a Login Overlay
page
by Scott Mitchell
Feedback
Average Rating: 
Views (Total / Last 10 Days): 41480/ 454

Introduction

Many types of websites, from online retailers to social networking sites, allow visitors to create user accounts. Such websites share a number of features in common: they all enable visitors to register a user account in some manner; they all must allow visitors some way to identify themselves in order to sign into the website; and they all have some feature or functionality that is only available to users who have signed in.

Traditionally, websites that support user accounts have their visitors sign in by going to a dedicated login page (such as www.example.com/Login.aspx) where they enter their username and password. Typically, users reach the dedicated login page either by clicking on a Login link somewhere on the page or by attempting to access a page they are not authorized to view. (By default, ASP.NET automatically redirects users making unauthorized request to the dedicated login page.)

One nitpick I have with dedicated login pages is that signing in involves leaving the current page to visit the dedicated login page. Consider the ASP.NET Forums. If a visitor who has an account with the site, but is not signed in, is viewing a post and decides she wants to add that post as a Favorite, she must first sign in. This involves clicking the "Sign In" link in the upper right corner, which takes her from the current page to the login page. Granted, once she's signed in she's redirected back to the post page, but with a bit of HTML, CSS, and JavaScript we could let the user sign in without leaving the post in the first place.

This article shows how to implement a login overlay, which is an alternative user interface for signing into a website. In a nutshell, when a visitor chooses to log into the website they are not taken to a dedicated login page, but rather have the login user interface displayed on the page they are currently visiting, laid atop the existing page content.

Figure 1 is a screen shot from the demo application available for download and shows the login overlay in action. In this screen shot the visitor has clicked the "Log In" link in the upper right corner, which has grayed out the page's content and displayed the login user interface atop it. After the visitor enters his credentials and clicks the "Log In" button, he is signed in and the page is reloaded so as to include any content that is present only for authenticated users.

 

This article shows how to use jQuery, ASP.NET, and the ASP.NET Ajax Library to create such a login overlay. The download for this article provides both an ASP.NET WebForms and ASP.NET MVC demo.

[Download Sample]

Displaying an Overlay

The key feature of the login overlay is that when the user opts to log into the site the login user interface is displayed in the same page the user is visiting, overlaying the existing page content. Therefore, our first order of business is to discuss how to define a login user interface within our web pages that is initially hidden, but is laid over the displayed page content when the user clicks the "Log In" link in the upper right corner.

Let's start by looking at the markup for the login user interface. Listing 1 shows the markup used to generate the login user interface displayed in Figure 1. This markup goes in your master page so that it is present on every web page on your site.

Listing 1 - The HTML for the login user interface.

<div id="loginUI">
    <div id="titlebar">
        <div id="closeIcon">X</div>
        Login!
    </div>
    <div id="body">
        <table>
            <tr>
                <td>Username:</td>
                <td><input type="text" id="loginUsername" /></td>
            </tr>
            <tr>
                <td>Password:</td>
                <td><input type="password" id="loginPassword" /></td>
            </tr>
            <tr>
                <td>&nbsp;</td>
                <td>
                    <input type="checkbox" id="loginRememberMe" />
                    <label for="loginRememberMe">Remember me</label>
                </td>
            </tr>
            <tr>
                <td>&nbsp;</td>
                <td>
                    <input type="button" id="loginLogin" value="Log In" />
                </td>
            </tr>
        </table>
 
        <div id="invalidCredentials">
            Your username and/or password are invalid.
        </div>
 
        <p>
            Don't have an account?
            <asp:HyperLink ID="lnkRegister" runat="server" 
    NavigateUrl="~/Account/Register.aspx">Create one now!</asp:HyperLink>
        </p>
    </div>
</div>

The bulk of the markup is the <table> element that contains the username and password textboxes, the "Remember me" checkbox, and the "Log In" button. Note how all of these inputs are HTML. There are no Web controls in the login user interface save for the HyperLink control that links to the Register.aspx page.

The login user interface is encased in a <div> element with an id of loginUI. There is a CSS file (LoginUIStyles.css) that defines the styling for this <div> element (see Listing 2). In particular, the loginUI <div> element has its display attribute is initially set to none, which is why the login user interface is not visible when viewing a page until the "Log In" link is clicked. As we'll see momentarily, when the "Log In" link is clicked JavaScript is used to change the display attribute, as well as to position the login user interface in the center of the browser window.

Listing 2 - The CSS styling for the login user interface.

#loginUI {
    width: 300px;
    border: 1px solid black;
    display: none;
    position: absolute;
    z-index: 5001;
}

The loginUI <div>, by itself, merely shows the login user interface. In order to gray out the page content we need another HTML element, which I've named loginUIOverlay (see Listing 3). As with the loginUI <div>, the loginUIOverlay <div> is hidden initially. But when the user clicks the "Log In" link the element is displayed and resized to cover the entire browser window.

Listing 4 shows the CSS styling for the loginUIOverlay <div>. Note how it is configured to be translucent, which is why you see the page content underneath the loginUIOverlay <div>. Also note that the loginUIOverlay <div> element's z-index attribute is set to 5000, which is one less than the z-index for the loginUI <div>. This ensures that the login user interface appears above the loginUIOverlay <div> (and that both <div>s appear above the page content).

Listing 3 - The HTML for the loginUIOverlay <div>

<div id="loginUIOverlay"></div>

Listing 4 - The CSS styling for the loginUIOverlay <div>

#loginUIOverlay {
    position: absolute;
    display: none;
    top: 0px;
    left: 0px;
    width: 0px;
    height: 0px;
    background-color: #aaa;
    opacity: .70;
    filter: alpha(opacity=70);
    z-index: 5000;
}

With the HTML and CSS for the login overlay in place, all that remains is the JavaScript to display the overlay when the user clicks the "Log In" link. The showLoginUI JavaScript function in Listing 5 is executed whenever the user clicks the "Log In" link.

showLoginUI starts by getting references to the HTML elements of interest, namely the loginUIOverlay <div>, the loginUI <div>, the invalidCredentials <div>, and the loginUsername textbox.

Next, the browser window's height and width are determined. The loginUIOverlay <div> element's height and width attributes are then assigned these values and the <div> element is displayed. This has the effect of "graying out" of the existing page content.

Following that, the loginUI <div> element's left and top attributes are set so that the login user interface is horizontally and vertically centered within the browser window. The loginUI <div> element is displayed using jQuery's fadeIn function, which adds a little pizzazz to the user experience.

And lastly, the invalidCredentials <div> element is hidden and focus is set to the loginUsername textbox.

Listing 5 - The showLoginUI function displays the login overlay.

function showLoginUI() {
    var loginUIOverlay = $("#loginUIOverlay"),
        loginUI = $("#loginUI"),
        invalidCredentials = $("#invalidCredentials"),
        loginUsername = $("#loginUsername");
    
    var docWidth = $(document).width(),
        docHeight = $(document).height();
 
    loginUIOverlay.width(docWidth)
                  .height(docHeight)
                  .show();
 
    loginUI.css({
        "left": (docWidth / 2) - (loginUI.width() / 2) + "px",
        "top": (docHeight / 2) - (loginUI.height() / 2) + "px"
    })
          .fadeIn();
 
    invalidCredentials.hide();
 
    loginUsername.focus();
}
Using ASP.NET's AuthenticationService Feature

When the login user interface is displayed and the user has entered her credentials and clicked the "Log In" button, we need to send the credentials to the server to determine whether they are valid. If they are, then we need to sign the user into the site. How you validate a user's credentials and how you sign them into the site depends on what techniques you are using to support user accounts. For most ASP.NET sites, developers use forms authentication and Membership.

With forms authentication, an authenticated user is identified by means of an authentication ticket, which is typically stored as a cookie on the user's browser. This authentication ticket is created when the user signs into the site; on subsequent visits, the browser includes the ticket in its request to the website, which is what allows the website to identify the visitor.

Membership is an API in the .NET Framework for managing user accounts. The Membership API uses the provider model and can be used to store credentials in a SQL Server database or Active Directory, among other user stores. The Membership class in the .NET Framework includes a ValidateUser method that accepts a username and password as input parameters and returns a Boolean value indicating whether the supplied credentials were valid.

Regardless of how you support user accounts, for the login overlay to work we need to be able to send the username and password entered by the user to the server to have those credentials validated and the user signed in. One option is to write your own server-side service, which you could do using an ASP.NET page, ASP.NET MVC actions, a generic HTTP Handler, or as an ASMX or WCF service. See my article, Accessing Server-Side Data from Client Script for more information on this topic.

Another option is to take advantage of ASP.NET's AuthenticationService feature, which was added to ASP.NET 3.5. The AuthenticationService feature offers client-side scripts and a server-side service for accessing the forms authentication and Membership systems. To use this functionality you must first enable it. Listing 6 shows the configuration to add to Web.config to turn on the AuthenticationService feature.

Listing 6 - Enable the AuthenticationService functionality for your website.

<configuration>
    ...

 

    <system.web.extensions>
        <scripting>
            <webServices>
                <authenticationService enabled="true" />
            </webServices>
        </scripting>
    </system.web.extensions>
</configuration>

The server-side AuthenticationService service offers three methods: IsLoggedIn, Login, and Logout.

·         The IsLoggedIn method returns the value of the Request.IsAuthenticated property, which is a Boolean value that indicates whether the request is from an authenticated user.

·         The Login method accepts three input parameters: the username, password, and whether to create a persistent cookie. This method calls the Membership.ValidateUser method, passing in the supplied username and password. If the credentials are valid then the FormsAuthentication.SetAuthCookie method is called, which creates the forms authentication ticket and stores it in the browser's cookies collection.

·         The Logout method calls the FormsAuthentication.SignOut method, which instructs the browser to remove its authentication ticket cookie, effectively logging the user out of the site.

When enabled, the server-side AuthenticationService service is exposed via the URL Authentication_JSON_AppService.axd. That is, you can invoke the IsLoggedIn, Login, and Logout server-side methods from client script by making a properly-formatted HTTP request to www.example.com/Authentication_JSON_AppService.axd. While you can certainly write your own JavaScript to accomplish this, there are existing client-side functions in the ASP.NET Ajax Library to facilitate communicating with the server-side AuthenticationService service.

To use the ASP.NET Ajax Library to interface with the AuthenticationService service in ASP.NET MVC applications you need to include the MicrosoftAjax.js and MicrosoftAjaxApplicationServices.js script files, which you can download (or link to) from http://ajax.aspnetcdn.com/ajax/4.0/1/MicrosoftAjax.js and http://ajax.aspnetcdn.com/ajax/4.0/1/MicrosoftAjaxApplicationServices.js. You also need to explicitly set the Sys.Services._AuthenticationService.DefaultWebServicePath property to the URL of the server-side AuthenticationService service, Authentication_JSON_AppService.axd. (See line 13 in the ~/Views/Shared/_Layout.cshtml file.)

To the ASP.NET Ajax Library to interface with the AuthenticationService service in ASP.NET WebForms applications, simply add a ScriptManager control to your master page. The ScriptManager automatically includes the necessary script files and assigns the Sys.Services._AuthenticationService.DefaultWebServicePath property for you. (Alternatively, you could bypass adding a ScriptManager control and manually add the necessary script files and script code like with an ASP.NET MVC application.)

Validating Users' Credentials

The MicrosoftAjaxApplicationServices.js script file includes a Sys.Services.AuthenticationService.login function that makes an asynchronous HTTP request to the server-side service, passing in the supplied credentials. If the credentials are valid then the user is signed into the site.

Listing 7 shows the code for the attemptLogin and onLoginComplete functions. The attemptLogin function is called when the user clicks the "Log In" button from the login user interface and is responsible for calling the Sys.Services.AuthenticationService.login function. The onLoginComplete function is a callback function that is executed when the browser receives the response from the server-side service. This function is passed a Boolean value indicating whether the credentials were valid or not. If the credentials were valid then the page is reloaded, otherwise the invalidCredentials <div> element is displayed.

Listing 7 - The Sys.Services.AuthenticationService.login function is called when the user clicks the "Log In" button from the login user interface.

function attemptLogin(redirectUrl) {
    var loginUsername = $("#loginUsername"),
        loginPassword = $("#loginPassword"),
        loginRememberMe = $("#loginRememberMe");
 
    Sys.Services.AuthenticationService.login(
            loginUsername.val(),               // username
            loginPassword.val(),               // password
            loginRememberMe.is(":checked"),    // isPersistent
            null,                              // reserved for future use
            redirectUrl,                       // redirectUrl
            onLoginComplete,                   // loginCompleteCallback
            null,                              // failedCallback
            null);                             // userContext
}
 
function onLoginComplete(validCredentials) {
    var invalidCredentials = $("#invalidCredentials"),
        loginPassword = $("#loginPassword");
 
    if (validCredentials === true) {
        window.location.replace(window.location.href);
    }
    else {
        invalidCredentials.show();
        loginPassword.val('');
    }
}

Take a moment to examine the input parameters passed to the Sys.Services.AuthenticationService.login function. The first three parameters - userName, password, and isPersistent - are the three values passed into the server-side service's Login method, and are self-explanatory.

If specified, the redirectUrl parameter indicates the URL the user is redirected to upon successfully logging in.

The loginCompleteCallback parameter specifies the function to call when the response returns from the server, whereas failedCallback is the function to call if the attempted service call fails. Note that the loginCompleteCallback function is executed whether the supplied credentials are valid or not; the failedCallback function is only invoked if there was an error in making the HTTP request to the server-side service or if the service threw an exception.

The userContext parameter can be used to pass information to the loginCompleteCallback or failedCallback functions.

The attemptLogin function accepts a redirectUrl input parameter, which is passed into the Sys.Services.AuthenticationService.login function's redirectUrl input parameter. The net effect is that if a redirectUrl input parameter value is supplied to the attemptLogin function then the user is redirected to the specified URL after successfully signing in. If this parameter value is not provided then the current page the user is visiting is reloaded after sign in. In the demo available for download, the attemptLogin function is called when the user clicks the "Log In" button in the login user interface. This function is called without specifying a redirectUrl input parameter, as Listing 8 shows, which means that after logging in the user will remain on the current page. However, you could modify this script so that the user is redirected to a particular page, such as /Default.aspx, upon sign in.

Listing 8 - The attemptLogin function is called when the "Log In" button is clicked.

$(document).ready(function () {
     ...
  
     $("#loginLogin").click(function () {
         // Reloads the current page on login
        attemptLogin();

 

        // Redirects the user to the homepage on login
        // attemptLogin('/Default.aspx');  
     });
 });
Logging Users Off

In addition to the Sys.Services.AuthenticationService.login function, the MicrosoftAjaxApplicationServices.js script file includes a Sys.Services.AuthenticationService.logout function. Like the Sys.Services.AuthenticationService.login function, when calling the Sys.Services.AuthenticationService.logout function you can supply a redirectUrl parameter and callback functions to execute on success or failure.

In the downloadable demo, the master page displays a "Log Out" link in the upper right corner for logged in users. Clicking this "Log out" link executes the attemptLogout function, which calls the Sys.Services.AuthenticationService.logout function (see Listing 9).

Listing 9 - The attemptLogout function logs out the user.

function attemptLogout(redirectUrl) {
    Sys.Services.AuthenticationService.logout(
        redirectUrl,        // redirectUrl
        null,               // logoutCompletedCallback
        null,               // failedCallback
        null);              // userContext
}

As with the attemptLogin function, the attemptLogout function accepts a redirectUrl input parameter, which is passed into the Sys.Services.AuthenticationService.logout function's redirectUrl input parameter. The net effect is that if a redirectUrl input parameter value is supplied to the attemptLogout function then the user is redirected to the specified URL after successfully logging out. If this parameter value is not provided then the current page the user is visiting is reloaded after logging out.

When the "Log Out" link in the demo is clicked the attemptLogout function is called without specifying a redirectUrl input parameter. Consequently, the page the user is visiting when logging out is reloaded after log off. However, you could modify this script so that the user is redirected to a particular page upon log off.

Security and Other Concerns

Bear in mind that except for requests over HTTPS, any request from the browser to the server is transmitted over the network in plain-text. For this reason, many websites have the login page accessed via HTTPS, as in https://www.example.com/login.aspx. This approach ensures that the user's credentials are securely transmitted and kept from prying eyes. With the login overlay user interface, user credentials are sent to the server-side service in plain-text unless the user is visiting the current page over HTTPS.

You can optionally configure the server-side AuthenticationService service to only accept requests over SSL. To accomplish this, go to Web.config and set the system.web.extensions\scripting\webServices\authenticationService element's requireSSL attribute to true. If requireSSL is set to true and a non-secure request is made to the server-side AuthenticationService service then the service throws an HttpException. If you go this route also consider setting the system.web\authentication\forms element's requireSSL attribute to true as well, which instructs the browser to submit the authentication ticket to the server only when making a request over HTTPS.

In closing, realize that for many sites the login overlay is not intended to be an outright replacement for the dedicated login page. If you have pages that are only available to authenticated users then you will still need a dedicated login page for those scenarios where an anonymous user attempts to directly visit a page intended only for authenticated users.

Download

[Download Sample]

Further Reading

For more information on the topics addressed in this article, consult the following resources:

·         Accessing Server-Side Data from Client Script

·         ASP.NET Security Tutorials

·         The Client-Side Sys.Services.AuthenticationService class

·         Introduction to Membership

·         The Server-Side AuthenticationService class

·         Using Forms Authentication in ASP.NET

 


Product Spotlight
Product Spotlight 

©Copyright 1998-2014 ASPAlliance.com  |  Page Processed at 7/24/2014 9:33:27 PM  AspAlliance Recent Articles RSS Feed
About ASPAlliance | Newsgroups | Advertise | Authors | Email Lists | Feedback | Link To Us | Privacy | Search