Wrox Press
ASPToday
       967 Articles
  in the Solutions Library
  Log off
 
 
 
ASPToday Subscriber's Article Andrew Krowczyk
Creating an ASP.NET Login UserControl and Forms Authentication
by Andrew Krowczyk
Categories: .NET Framework, Security/Admin
Article Rating: 4
Published on September 17, 2002
 
Content Related Links Discussion Comments Index Entries Downloads
 
Abstract
In this article, Andrew Krowczyk will present code that was developed to take control of authenticating a user against a SQL Server 2000 permissions database. Topics discussed include: creating Web User Controls in ASP.NET; connecting to SQL Server; and enabling Forms Authentication on your ASP.NET web application.

Prerequisites
It is assumed that you have a basic knowledge of ASP.NET development, as well as basic knowledge of SQL Server 2000 and general authentication topics. The .NET Framework and SQL Server 2000 (any edition) are required to get the full benefit out of the sample code presented.
 
 
Article

Introduction

Every developer knows that code reuse is good, right? I know that I've always tried to write modular code that could be reused all over the place in my applications. Well, maybe not really all the time. Why? There are many reasons that code has always been hard to build in a reusable fashion. Usually I find that code is closely knit to the applications, unless, of course, we are talking about basic functionality that is shared across applications. Examples of this in my past corporate development experience have been items such as:

  • Sending E-mail from within applications
  • Performing common backend tasks
  • Application logging and Event writing
  • Application security (Logging in/out)

The last item mentioned above is one that I find myself implementing over and over within my current work environment, and in general with any web application that I write. In the past, encapsulating and reusing the code needed to log into web applications and secure them was quite a bit harder than it is now with the advent of .NET.

With .NET I can create a Web UserControl to encapsulate the login portion of the logic. This coupled with use of .NET's web.config file to implement a broad Forms Authentication scheme across my site allows me to easily add Login/Logout cookie based Forms Authentication to any web app.

In this article I will present my Login UserControl and additional information to make it much easier for you to secure your ASP.NET applications too!

System Requirements

I'm assuming that you have a basic knowledge of ASP.NET development as well as basic knowledge of SQL Server 2000 and general authentication topics. The release version of .NET and SQL Server 2000 (any edition) are required to get the full benefit out of the sample code presented.

Defining The Problem

Every time I create a new web application for my employer, I find myself trying to reinvent the wheel with regards to controlling user access and authorization. Although ASP.NET and IIS allow some basic Windows Integrated Authentication schemes that can keep out unwanted users, I typically like to control user access based on a SQL Server database. It's common in my workplace to control our own user database, and that's generally what is done.

I find it quite boring to retype the same code over and over. Don't you wish that there was a way in .NET that you could create some sort of "control" that you could place on a web page that encapsulated functionality? You know, kind of like WindowsDNA ActiveX controls? Wait a minute, there is such functionality...

What's a UserControl?

ASP.NET introduces a technology called Web User Controls. An ASP.NET user control is a group of one or more server controls or static HTML elements that encapsulate a piece of functionality. A user control could simply be an extension of the functionality of an existing server control. Or it could consist of several elements that work together to perform a task. It's easiest to relate this back to the days of ActiveX controls, where you could create a control that extended the functionality of a certain control, or grouped controls together.

That being said, how could I use a user control to aid in my quest for creating a reusable login construct? Let's start with a vision of what I'd like to create and then go from there.

My Ideal Login Form

Ideally I'd like to create a login form that could be inserted anywhere on a site where user validation and authentication is required. It'd also have to be pretty, because I hate ugly web sites : )

I played around with my favorite HTML editor (notepad) and came up with this construct. Let's pretend that we all work for Wrox, and are creating this for their sites:

Isn't that wonderful? The next question is how do we turn that into a UserControl that can be dropped into web pages and reused in different company applications?

Creating the Login UserControl

First off, we need to open up VS.NET and create a new ASP.NET web project. I started VS.NET and choose to create a new C# ASP.NET application. This can be done in VB.NET as well, but my company standardized on C# for .NET development, and I'm presenting it that way.

Once the project creation is complete, we'll add a new Web User Control to the project by right clicking on the Project in the Project Explorer and selecting ADD | ADD Web User Control.

We'll call our UserControl LoginUC.ascx.

What goes in there?

Ok, so now we basically have a shell project with a blank user control added to it. At this point, I renamed the default WebForm1.aspx page to Login.aspx page. You don't have to do that, but in anticipation for what we are going to talk about later, it's a good idea.

Next, we simply need to insert our code into the user control. There are 2 parts to this. The first is the HTML code and the ASP.NET tags that go in the user control, and then there is the code that must go in the codebehind file to perform the authentication checks.

HTML

When you click on the user control in the Project Explorer, you are taken to a blank screen (design mode) for the user control. To insert HTML into the control, we need to first click on the HTML tab of the IDE window.

Now we can insert our HTML code into the editor window to create the HTML table structure for our UserControl.

Notice that the first line of the file should already have been populated by the VS.NET IDE

<%@ Control Language="c#" AutoEventWireup="false" 
Codebehind="LoginUC.ascx.cs" Inherits="LoginUserControl.LoginUC" 
TargetSchema="http://schemas.microsoft.com/intellisense/ie5"%>

This code is needed by .NET to tell the Framework where the codebehind is for the control.

Next I'll simply drop in the nice HTML code that I wrote in notepad. I also created a graphic to insert into the table structure (which I added to the project).

<table borderColor="gainsboro" cellSpacing="0" cellPadding="0" width="205" 
border="1">
  <tr>
    <td align="left" height="25"><font face="Arial" color="black"><b><IMG 
src="wrox_logo.gif"></b></font></td>
  </tr>
  <tr>
    <td align="middle" height="25">
      <table width="100%" bgcolor="Gainsboro">
      <tr>
        <td><font face="Arial" size="-1">UserName:</font></td>
        <td><b><asp:textbox id="UserName" runat="server" 
size="14"></asp:textbox></b></td>
        <td><asp:label id="UserMark" style="FONT: 12pt verdana, arial; 
COLOR: red" runat="server" Visible="false" Text="*"></asp:label></td>
      </tr>
      <tr>
        <td><font face="Arial" size="-1">Password:</font></td>
          <td><input id="Password" type="password" size="14" name="Password" 
runat="server"></td>
        <td><asp:label id="PasswordMark" style="FONT: 12pt verdana, arial; 
COLOR: red" runat="server" Visible="false" Text="*"></asp:label></td>
      </tr>
      <tr>
        <td></td>
        <td><input id="Submit1" type="submit" value="     Sign In     " 
name="Submit1" runat="server" onServerClick="Submit1_ServerClick"></td>
      </tr>
      <tr>
        <td align="middle" colSpan="3"><asp:label id="Message" style="FONT: 
8pt verdana, arial; COLOR: red" runat="server" Visible="false"></asp:label></td>
      </tr>
       </table>
     </td>
  </tr>
</table>

As you can see, the HTML is fairly straightforward. Note that we are using ASP.NET server side web controls such as label, textbox, and the password input for the fields. We are also hooking up our submit button to the Submit1_ServerClick event that will be defined in the codebehind class.

Clicking back on the design tab should give you output like this:

Now that we've sorted out the look of the control, we must implement the code that checks our username and password against the SQL Server 2000 database.

For simplicities sake, I created just one table in the DB that contains 2 fields: the username and password. I called the database "LoginTest " I'll assume that in your applications you'll create this however you want, and probably take the time to do some encryption with the passwords. But here we'll just create the schema and table to look like the following (the code download contains a sql script called database.sql that will recreate this for you, you do however need to create the table called "LoginTest " before running the script to generate the table).

Above you see a database called LoginTest and a table called users.

Ok, so we have our database set up. Now let's complete the codebehind file.

Let's declare our namespace and insert the required using statements.

namespace LoginUserControl
{
       using System;
       using System.Data;
       using System.Drawing;
       using System.Web;
       using System.Web.UI.WebControls;
       using System.Web.UI.HtmlControls;
       using System.Data.SqlClient;
       using System.Web.Security;
       using System.Configuration;

Actually, by default most of the using statements were there. The 3 that I added were the System.Data.SqlClient, System.Web.Security and System.Configuration namespaces. Why did I add these? Well, SqlClient should be self-explanatory, the Web.Security namespace was added for our Forms Authentication use later on in the article, and the Configuration namespace was added so that I could access the Web.Config file.

Now I need to add some more code to flush out the structure of the class (all of this is here by default). Notice that I added two public variables for the redirect page and a flag for the warning message on the user control itself.

/// <summary>
///           Summary description for LoginUC (Login UserControl).
/// </summary>
public abstract class LoginUC : System.Web.UI.UserControl
{
       protected System.Web.UI.WebControls.TextBox UserName;
       protected System.Web.UI.WebControls.Label UserMark;
       protected System.Web.UI.WebControls.Label PasswordMark;
       protected System.Web.UI.WebControls.Label Message;
       protected System.Web.UI.HtmlControls.HtmlInputText Password;
       protected System.Web.UI.HtmlControls.HtmlInputButton Submit1;
              
       //needed variables for both redirection and an int flag
       //read redirect page from web.config (more on that later)
       public String RedirectPage 
              = ConfigurationSettings.AppSettings["redirectpage"];
       public int chk;

       private void Page_Load(object sender, System.EventArgs e)
       {
              // nothing to do here
       }

Remember back in the HTML when I called a function called Submit1_ServerClick ? Well let's code that right now.

What we want to do in this function is twofold. First we want to validate the username and password. If they are correct, then we'll redirect to whatever page is specified in our control. If the authentication fails, we want to see if it was a bad password, or invalid username. Check the comments in the code below to see what's going on. For now, ignore the FormsAuthentication code, we'll discuss that in a bit.

public void Submit1_ServerClick(object sender, System.EventArgs e)
{
       //call another method that authenticates
       if (Authenticate(UserName.Text, Password.Value)) 
       { 
             //redirect the page
             Response.Redirect (RedirectPage);
             
             //forget the code below for now, we'll talk about it later
             //FormsAuthentication.RedirectFromLoginPage(UserName.Text,false
             //);
       }
       else 
       {
              //ok, an error.  What error was it?  Handle accordingly.
              if (chk==1)
              {
                     Message.Text="The password is invalid";
                     UserMark.Visible = false;
                     PasswordMark.Visible = true;
                     Message.Visible = true;
              }
              else
              {
                     Message.Text="The username is invalid";
                     PasswordMark.Visible = false;
                     UserMark.Visible = true;
                     Message.Visible = true;
              }
       }
}

Now let's write the Authenticate( ) function called from the above code. Before we get to it, we should first quickly go over some custom settings that I added to the web.config file for the web application. These simply help me avoid hardcoding the DSN and the Redirect Page that I showed earlier.

<appSettings>
    <add key="dsn" value=    
          "server=USZHOIT28971\\ANDYDEV;uid=sa;pwd=;database=LoginTest" />
    <add key="redirecturl" value="main.aspx" />
</appSettings>

Anyway, now onto the Authenticate code. Read the comments below for direction on what the code is doing.

bool Authenticate(String user, String pass) 
{ 
       //set up a fall through variable for determining
       //authentication
       bool authenticated = false;
       try 
       { 
              //read the dsn from the Web.Config file
              String dsn = ConfigurationSettings.AppSettings["dsn"];
              
              //create our SQL select statement
              String sSQL = "SELECT username,password FROM users where 
                     username='" + user.Trim() + "'";
           
              //create a new connection with the DSN
              System.Data.SqlClient.SqlConnection Conn = new 
                     System.Data.SqlClient.SqlConnection(dsn);

              //now create a sql command with the connection and SQL
              System.Data.SqlClient.SqlCommand Cmd = new 
                     System.Data.SqlClient.SqlCommand(sSQL,Conn);

              //create a new SqlDataReader object 
              System.Data.SqlClient.SqlDataReader Read1 = null;
              
              //open the connection and execute the reader
              Conn.Open();
              Read1 = Cmd.ExecuteReader();

              //check results and determine what was wrong if anything
              //set the chk flag (invalid username or invalid password)
              if (Read1!=null)
              {
                     if (Read1.Read()) 
                     { 
                            if (Read1.GetString(0)==user)
                            {
                                   if(Read1.GetString(1)==pass)
                                   {
                                          authenticated =true;
                                   }
                                   else
                                   {
                                          chk=1;
                                    }
                            }
                            else
                            {
                                   chk=2;
                            }
                     }

              }
  }
  catch(Exception e) 
{
       Response.Write("Exception: " + e.ToString());
}

return authenticated;
}

  }
 }

We've finished the code for our control!

Testing the UserControl

Now that we've written the code for the Login UserControl, we need some way to test it. This is quite simple. Remember the default .aspx page that was created when we started our project? The one that I renamed to Login.aspx ? To test the user control, we can simply put an instance of the user control on the Login.aspx page, set the start page to Login.aspx and hit run (F5).

You can add the user control, by clicking and dragging the LoginUC.ascx item in the Project Explorer over to the Login.aspx page designer.

Starting up the project should bring up the following browser window:

Provided that you set up your SQL Server database correctly, you should be able to enter some information in the username and password fields and test out the user control.

For example, entering a wrong password will give you this:

As well as entering the wrong username:

Wow, that's fine and dandy isn't it? Currently when we enter both the correct username and password, the Login UserControl will redirect the ASP.NET page to the page specified in the web.config redirecturl AppSetting. Which in our case would be Main.aspx (a blank page I added to the project).

What about Security?

So, now we have a user control that validates user data against a SQL Server 2000 database, but it really doesn't secure the site very well. If we are going to use this in an ASP.NET web site, we need some way to deny access to certain pages. How do we do that?

Well, luckily for us there is an easy way to do this using Forms Authentication in .NET. As you probably already know, the web.config file allows you to control many aspects of how your ASP.NET web site works. One section that you can control is the Authentication section. This section controls the authentication settings for the application. You can set up possible authentication schemes for "Windows", "Forms", "Passport" and "None". We're going to use Forms Authentication in ours.

I'm not going to delve deeply into the Authentication/Authorization sections, other than to describe the code that we are adding for this application. If you want to see all of the available options for these sections of the web.config file, I suggest that you take a look at the Microsoft documentation at http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vsent7/html/vxconASPNETAuthentication.asp&WROXEMPTOKEN=64823Zg6Qt4ZwJFo47xTvh87ND.

What do we want?

You can use the Login UserControl for anything that needs to validate login information. But in the instance where we want to lock down the site pages from users that aren't logged in, we'd want something like the following.

Basically, to hit any of the pages in the site, we want the user to first go through the login screen. If the user has logged in successfully, then we would want to allow him to freely browse the pages in our site without having to re-authenticate on each page. How could we do that?

Well, the first thing we must do is set up the authentication and authorization sections in the web.config file.

Let's set the authentication mode to Forms, and protect all the pages, setting the loginURL to hit our login.aspx page that contains the Login UserControl. The name portion sets a unique extension for the cookie that will be written to the user's browser upon proper forms authentication. Also note that the timeout value has been set to 10 minutes. The authentication in ASP.NET takes care of the timeout value, forcing another login after the timeout period has expired.

<authentication mode="Forms">
       <forms name=".LOGINUSERCONTROLDEMO" loginUrl="login.aspx" 
protection="All" timeout="10" path="/"></forms>
</authentication>

Let's specify that we deny all users:

<authorization>
       <deny users="?" />
</authorization>

Next we need to make a few changes to the code we described earlier. We need to use the FormsAuthentication.RedirectFromLoginPage instead of the Response.Redirect that we had. This will allow our application to write a cookie out and redirect back to the page that was initially being requested before getting pushed over to the login form for authentication.

//call another method that authenticates
if (Authenticate(UserName.Text, Password.Value)) 
{ 
       //redirect the page
       //Response.Redirect(RedirectPage);
              
       //stick username in the cookie, and set the persitent value 
       //to false for our testing              
FormsAuthentication.RedirectFromLoginPage(UserName.Text,false);
}

Main.aspx

Here's the code to a page called Main.aspx. It contains a simple little message, and a button to "log out" of the forms authentication mode and kick back to the login page.

HTML

<%@ Page language="c#" Codebehind="main.aspx.cs" AutoEventWireup="false" 
Inherits="LoginUserControl.main" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
<HTML>
       <HEAD>
              <title>main</title>
              <meta name="GENERATOR" Content="Microsoft Visual Studio 7.0">
              <meta name="CODE_LANGUAGE" Content="C#">
              <meta name="vs_defaultClientScript" content="JavaScript">
              <meta name="vs_targetSchema" 
content="http://schemas.microsoft.com/intellisense/ie5">
       </HEAD>
       <body MS_POSITIONING="GridLayout">
              <form id="main" method="post" runat="server">
                     This the main page.
                     <asp:Button id="logout" style="Z-INDEX: 101; LEFT: 7px;
 POSITION: absolute; TOP: 64px" runat="server" Text="Logout" 
Width="78px" Height="25px"></asp:Button>
                     
              </form>
       </body>
</HTML>

CodeBehind

Notice that the logout_Click event forces the logout and redirect to the login page.

using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using System.Web.Security;

namespace LoginUserControl
{
       /// <summary>
       /// Summary description for main.
       /// </summary>
       public class main : System.Web.UI.Page
       {
              protected System.Web.UI.WebControls.Button logout;
       
              private void Page_Load(object sender, System.EventArgs e)
              {
                     // Put user code to initialize the page here
              }

              #region Web Form Designer generated code
              override protected void OnInit(EventArgs e)
              {
                     //
                     // CODEGEN: This call is required by the ASP.NET Web 
                     //Form Designer.
                     //
                     InitializeComponent();
                     base.OnInit(e);
              }
              
              /// <summary>
              /// Required method for Designer support - do not modify
              /// the contents of this method with the code editor.
              /// </summary>
              private void InitializeComponent()
              {    
                     this.logout.Click += new 
System.EventHandler(this.logout_Click);
                     this.Load += new System.EventHandler(this.Page_Load);

              }
              #endregion

              private void logout_Click(object sender, System.EventArgs e)
              {
                     FormsAuthentication.SignOut();
                     Response.Redirect("login.aspx");
              }
       }
}

We see that the main.aspx page looks like the following.

Wrapping it Up

As you can see, using the login user control coupled with Forms Authentication allows you to easily add login capabilities to an ASP.NET site. Although the control isn't as complex as some other Web UserControls out there, it really helps out in keeping interdepartmental applications in sync with their login methodologies. Which is the whole reason for code reuse in our work environment!

Application Setup

Setting up the sample application is quite simple. These directions are also included in the Readme.txt file of the download.

Installation Instructions

1) The easiest way to get the sample code up and running is to create a directory under wwwroot called LoginUserControl

2) Use the MMC IIS Snap in and right click on the folder - go to Properties

3) Select the Create button on the Application tab of the property window

4) If desired, open the LoginUserControl.sln file

DB

Using SQL Server Enterprise Manager, create a database called LoginTest, run the sql script called database.sql distributed with the sample code.

Configuration

Edit the web.config file to include your database connection information. See the <appSettings> section.

Hit the location of the site, for example, http://localhost/loginusercontrol/Login.aspx?WROXEMPTOKEN=64823Zg6Qt4ZwJFo47xTvh87ND

Conclusion

In this article we presented a few topics related to login authentication and creating a login UserControl for accessing a web site. Data was stored in SQL Server 2000 and although the architecture was quite simple, there are many ways this could be expanded to fit within your ASP.NET applications and hopefully you'll find it as useful as I have for creating consistent login screens across your apps.

 

Please rate this article using the form below. By telling us what you like and dislike about it we can tailor our content to meet your needs.

Article Information
Author Andrew Krowczyk
Chief Technical Editor John R. Chapman
Project Manager Helen Cuthill
Reviewers Ikka Merilainen & Dinar Dalvi

If you have any questions or comments about this article, please contact the technical editor.

 
 
Rate this Article
How useful was this article?
Not useful Very useful
Brief Reader Comments: Read Comments
Your name (optional):
 
 
Content Related Links Discussion Comments Index Entries Downloads
 
Back to top