Understanding and Implementing ASP.NET Custom Forms Authentication

This article talks about ASP.NET the custom Forms Authentication mechanism. We will see how we can use a custom database in unison with the ASP.NET Forms Authentication mechanism to provide the desired level of security to our applications.

Background

We have already seen how we can use ASP.NET Roles and Membership classes to provide authentication and authorization in our applications (refer this). Also, we know about the server controls provided by ASP.NET to facilitate easy implementation of Roles and Membership functionalities in our application.

These Roles and Membership classes come in very handy when we want to provide authentication and authorization in our applications. ASP.NET also provides a way to implement custom Roles and Membership to take more granular control over things.

We might still find ourselves in situations where we need to have our own database for tracking users and their roles. The reasons could be:

  • We have an existing database and we are trying to implement an application using that.
  • The Roles and Membership functionality is overkill for our application.
  • The Roles and Membership functionality is not sufficient for our applications and we need custom data.

In all the above scenarios, we find the need to use ASP.NET Forms Authentication but according to our database schema and our custom written code to handle user management. This is where the beauty of ASP.NET is shown. ASP.NET provides us fully functional and robust functionality for authentication and authorization and yet it gives us the possibility of taking full control and having full customization of the functionalities (which is actually not limited to Authentication related stuff, pretty much all areas of ASP.NET does that).

So what we are trying to do can easily be achieved by having a custom Forms Authentication mechanism. Using a custom Forms Authentication mechanism we can have our own tables to manage users and yet use the existing form authentication mechanism using GenericPrincipal. Let us try to work out an example and see how this can be done.

Using the code

Let us start by getting our requirements clear. We will be implementing a website that has the following structure:

structure

The top level default page and the login page can be accessed by anyone. The pages in other folders can only be accessed by users in respective roles. Just to understand it in a clear way, let us look at the web.config of the PlatinumUser folder.

And the database that we have for user management looks like this.

database

We have a user table and every user can have multiple Roles. We will be using this table to authenticate the users.

Note: The database is neither optimized nor normalized as that was not the main intent of this article. A real world example of database will be more optimized and perhaps more complex. The passwords will not be in clear text for sure too.

Now before going ahead, let us look at the little algorithm that we will be following to implement custom forms authentication and achieve the desired functionality.

  1. Configure the application to use Forms Authentication.
  2. Create a login page.
  3. Whenever a user tries to access the restricted area, push him to the Login page.
  4. When the user tries to login, verify his credentials using the database.
  5. If the login is successful, keep the username and his Roles in a Session variable to use it further.
  6. Create an authentication ticket for the user (an encrypted cookie). We can have this persistent or non persistent.
  7. Facilitate the User/Roles extraction using the authentication ticket.
  8. Use the user/Roles found in the last step and create a Principal using that so that the ASP.NET Forms Authentication mechanism can use this data.

Note: Each point in this algorithm can be found emphasized in the explanation below.

We have the algorithm worked out. We will now look at how each step is done. Let us start with Configure the application to use Forms authentication. To do this we need to set the authentication mode in the web.config file.

This web.config indicates that Forms Authentication will be used in this application. The default loginUrl is Login.aspx. The name of the authentication ticket cookie will be MyCustomAuthentication and if this cookie is created in non persistent mode, then the timeout period for that is 30 minutes.

Now we have our website set to use Forms authentication and we have also specified the default login page so we also took care of #3 of our algorithm, i.e., Whenever user tries to access the restricted area, push him to the Login page. The next thing is to Create a login page.

login

Once this login page is done, we need to have some mechanism so that When the user tries to login, verify his credentials using the database. To do this, I have created a small helper class. Ideally this logic will be placed in a Data Access layer or might be present in ORMs. But for the sake of simplicity I have created a small helper class do to this.

Now whenever the user tries to log in, If the login is successful, keep the username and his Roles in Session variable to use it further, and also we need to Create an authentication ticket for the user (an encypted cookie). So let us do all this in the Button click event of the login page.

Now before going further, there is one thing to understand. When Forms authentication is being used, whenever the need for authentication arises, the ASP.NET framework checks with the current IPrinciple type object. The user ID and Role contained in this IPrinciple type object will determine whether the user is allowed access or not.

So far we have not written code to push our user specific details in this principle. To do that we need to override a method called FormsAuthentication_OnAuthenticate in global.asax. This method is called each time ASP.NET framework tries to check authentication and authorization with respect to the current Principle.

What we need to do now is to override this method. Check for the authentication ticket (since the user has already been validated and the ticket was created) and then supply this User/Role information in the IPrinciple type object. We can implement our custom Principle type too but to keep it simple, we will simply create a GenericPriciple object and set our user specific details into it [#7 and #8 of our algorithm are covered].

Now when we run the application, we will see that the authorization mechanism is working as specified in the respective web.config files in perfect unison with our own custom database and authentication logic.

running

Note: Running the sample application, looking at code, and debugging the application is strongly recommended to get a full understanding of the above mentioned concepts.

Points of interest

When I came across the requirements of having custom forms authentication, I was rather intimidated. It was partly because I only knew how the ASP.NET default membership provider worked and partly because the hype about how difficult it is to do custom forms authentication. When I sat on it, I found it rather straightforward and easy.

There is one more major area that is also worth looking into to understand the authentication and authorization mechanism completely and that is implementing a custom Membership Provider. Perhaps I will do that in a separate article.

Download sample code for this article: CustomUserRoles

2 thoughts on “Understanding and Implementing ASP.NET Custom Forms Authentication