ASP.NET 2.0 Forms Authentication Using Access Database

March 4, 2007 at 5:56 PMAmer Gerzic

Introduction

Authentication and authorization is one of the basic components of web application development. When I first started web development, I quickly realized that authentication and authorization of resources were performed in variety of ways. Throughout years, I developed variety of web applications, primarily for my own use. With arrival of ASP.NET 1.0, authentication and authorization were simplified. ASP.NET 2.0 takes this feature even further by providing the user with powerful tools to quickly implement authentication and authorization. With these tools, a user can utilize MS SQL 2005 Server, XML data source, MS Access database and other data sources to retrieve user information. In this article I will focus on bare minimum needed to implement forms authentication using access database.

Roles and Membership Provider, and Forms Authentication

In order to simplify authentication, ASP.NET 2.0 provides us basically with two abstract classes: MembershipProvider and RoleProvider located in System.Web.Security namespace of .NET 2.0 library. These classes serve as common interfaces between ASP.NET 2.0 authentication and authorization engine and software developer. Both classes are declared to be abstract, which prevents instantiation and enforces overriding for purpose of creating custom security providers. Specifically, MembershipProvider class is responsible for user level authorization, while the responsibility of RoleProvider is role (or group) level authorization.

As alredy metioned, utilization of these two classes is cruical to implement custom authentication and authorization in ASP.NET 2.0. But how do we utilize these classes for our own purposes? Good example would is provided by ASP.NET 2.0 library itself. System.Web.Security namespace contains two classes SqlMembershipProvider and SqlRoleProvider that inherit from abstract classes MembershipProvider and RoleProvider and provide interface to authorization and authentication using MS SQL 2005 Server as source. Peeking into code reveals nothing else but expected. Both classes simply override all of functions defined in MembershipProvider and RoleProvider classes. As a matter of fact, MSDN library states that deriving from these two classes makes it mandatory to override each method. If this is not done, C# compiler will let you know anyways.

Utilizing Roles and Membership Providers

Looking through MSDN documentation, I was interested in bare minimum needed for simplest form of forms authentication using MS Access database. Through some trial and error I concluded that there are only two methods from RoleProvider class and one method from MembershipProvider that must be implemented to achieve such goal. In example provided below for download, I implemented third method, which is Initialize, simply to get connection string from web.config file. However, this was not necessary. Here is code for method overriden in MembershipProvider:

public override bool ValidateUser(string username, string password)
{
    using(OleDbConnection conn = new OleDbConnection(m_strDBConnection))
    {
        try
        {
            /* Create command */
            OleDbCommand command = 
                     new OleDbCommand("SELECT USERNAME, PASSWORD FROM Users " + 
                                      "WHERE USERNAME='" + username + 
                                      "' AND PASSWORD='" + password + "'", 
                                      conn); 

            /* Open connection */
            conn.Open(); 

            /* Run query */
            OleDbDataReader reader = command.ExecuteReader(); 

            /* Check if we have something */
            bool bResult = reader.HasRows; 

            /* Close connection */
            conn.Close(); 

            return bResult;
        }
        catch(Exception ex)
        {
            System.Diagnostics.Trace.WriteLine(ex.Message);
        }
        return false;
    }
} 

As we can see the method simply connects to database using database connection string and searches for user with specified username. If such user was found, the password is verified. If both of these conditions are satisfied, the method returns true, otherwise false. In other words, this method is looking up user in provided data source and verifying password. In this case, data source is Access database, but it can really be anything.

Code for RoleProvider methods are shown below:

public override bool IsUserInRole(string username, string roleName)
{
    using (OleDbConnection conn = new OleDbConnection(m_strDBConnection))
    {
        try
        {
            /* Create command */
            OleDbCommand command  
                   = new OleDbCommand("SELECT USERNAME, ROLE_NAME FROM UsersInRoles " +
                                      "WHERE USERNAME='" + username +
                                      "' AND ROLE_NAME='" + roleName + "'",
                                      conn); 

            /* Open connection */
            conn.Open(); 

            /* Run query */
            OleDbDataReader reader = command.ExecuteReader(); 

            /* Check if there are any rows */
            bool bResult = reader.HasRows; 

            /* Close connection */
            conn.Close(); 

            return bResult;
        }
        catch (Exception ex)
        {
            System.Diagnostics.Trace.WriteLine(ex.Message);
        }
    }
    return false;
} 

public override string[] GetRolesForUser(string username)
{
    string[] Roles = null; 

    using (OleDbConnection conn = new OleDbConnection(m_strDBConnection))
    {
        try
        {
            /* Create command */
            OleDbCommand command = 
                      new OleDbCommand("SELECT ROLE_NAME FROM UsersInRoles " +
                                       "WHERE USERNAME='" + username + "'",
                                       conn); 

            /* Open connection */
            conn.Open(); 

            /* Run query */
            OleDbDataReader reader = command.ExecuteReader(); 

            /* Store all data into String collection */
            StringCollection sc = new StringCollection();
            while (reader.Read())
                sc.Add(reader.GetString(0));
            Roles = new string[sc.Count];
            sc.CopyTo(Roles, 0); 

            /* Close connection */
            conn.Close();
        }
        catch (Exception ex)
        {
            System.Diagnostics.Trace.WriteLine(ex.Message);
        }
    }
    return Roles;
}

Both methods are self explanatory. First method simply verifies that user is in role and returns true if that is the case. Second method simply constructs an array of group names (roles) that user belongs to and returns it as result. Once again, we simply use Access DB to retrieve this information.

Web Application Configuration

In order to take advantage of our code, we must perform correct application configuration. In other words, we must let application know that we would like to redirect standard user/role authentication and authorization to newly created engine. Also, we must enable authentication and authorization for each web application. For such needs, we must look into web.config file.

First that needs to be performed is modifying authorization option in web.config's system.web tag. Here is the code:

<system.web>
    <!--
          The <authentication> section enables configuration 
          of the security authentication mode used by 
          ASP.NET to identify an incoming user. 
    -->
    <authentication mode="Forms">
      <forms name="FormsAuthentication" path="/"  
             loginUrl="Default.aspx" timeout="20" />
    </authentication>
    
    <authorization>
      <allow users="*"/>
    </authorization>
[...]
</system.web> 

Here, we are simply stating that user authentication type should be forms authentication type. Using authorization tag, we are allowing all users to access all resouces by default. Later, we will limit access of resources using same configuration file. But how do we specify that we would like to use our own Membership and Roles provider? Here are application settings for that:

<system.web>
   [...]
   <membership defaultProvider="AccessMembershipProvider">
      <providers>
        <clear/>
        <add name="AccessMembershipProvider" 
             type="AccessProvider.AccessMembershipProvider"
             connectionStringName="USERSDB"/>
      </providers>
    </membership>
    <roleManager enabled="true" defaultProvider="AccessRoleProvider">
      <providers>
        <clear/>
        <add name="AccessRoleProvider"
             type="AccessProvider.AccessRoleProvider"
             connectionStringName="USERSDB"/>
      </providers>
    </roleManager>
   [...]
</system.web> 

As we can see above, we are simply saying that we would like to modify membership and roles providers. At this point I would strongly encourage user to refer to MSDN articles on web application configuration to explore wast amount of options available for these configuration parameters. The web application configuration is beyound the scope of this article.

At this point there is only one thing left to do and that is configuration of permissions. Once again such configuration is performed using web.config file. Here is sample code:

<location path="WebPage.aspx">
<system.web>
  <authorization>
    <deny users="?"/>
    <allow roles="User,Admin"/>
    <deny users="*"/>
  </authorization>
</system.web>
</location>

Location tag is placed outside system.web tags in web.config file. For full source code please refer to sample provided below. The attribute path within location tag could be used to specify folder or a page. Another way to specify these parameters is to embbed web.config file within each folder specifying permissions for that folder.

Access Database

As already mentioned, user credentials and groups are stored within MS Access database. Database is very simple and it consists of three tables: Users, Roles, and UsersInRoles. Table User consists of two fields: username and password. Table Roles simply contians group names like Admin or User. Table UsersInRoles contains combination of user names and roles from two previous tables and it denotes to which group each user belongs. This is simplest table that can be used for ASP.NET authentication. However, it is not recommended to be used in real life applications (no encryption).

Download

Download Sample Application (20.59 kb)

Posted in: ASP.NET | C#

Tags: , , , , , ,

Add comment

biuquote
Loading