When I first heard that ASP.NET did role-based authorization, I was excited—until I found out that the only way to implement it was using Windows authentication. This requires all users and their roles to be placed in the IIS database—not the solution I had in mind. In this article, I present another approach to implementing role-based authorization in ASP.NET.
The ASP.NET solution caused a lot of duplicated effort because I already had all my users in my .NET application’s Account table. It is also prone to synchronization problems since I have to maintain a separate database outside of the .NET application environment. The duplicated effort is the responsibility of the user administrator. The major problem is that the duplicated effort is an ongoing thing. I needed a better solution.
The custom .NET role-based authorization solution
I decided to implement my own role-based authorization. I hope that, in the future, Microsoft will see the merits of an implementation like this and add it to ASP.NET.
The first step is to add a subdirectory-specific web.config file to the subdirectory for which you want role-based authorization. Within this web.config file (See Listing A) add an <allow roles=””/> tag just like you would for ASP.NET role-based authorization.
After this, the solution is really quite simple. Get the <allow roles=””> elements out of the web.config file's current directory and the username from Page.User.Identity.Name. Check the roles allowed, as specified by the web.config file, against the roles of the user found in your local database. A match allows the user access. Obviously, if no match occurs, the user gets the boot.
To be fair, this custom .NET solution also requires a little bit of duplicated effort. Unlike ASP.NET’s solution, however, the custom .NET solution’s duplicated effort is strictly on the part of the developer and is done once for each role-based restricted Web page.
Role-based authorized Web page modifications
Let’s take a look at an example of the authorization code you will need to add to every role-based authorized Web page. Listing B shows all the changes needed to add authorization to the CodeBehind of an application called Admin.aspx.
All you need to do is change the base class of the CodeBehind’s class (in this case Admin) from System.Web.UI.Page to Common.AuthorizedPage. Of course, all the magic happens in the AuthorizedPage class with the help of inheritance. So, let’s take a look behind the curtain.
Due to inheritance, you are able to plug in the AuthorizedPage class wherever the Page class was. AuthorizedPage is really just Page with a couple of methods tacked on. Anything you can do with Page you can also do with AuthorizedPage.
The Roles() method is the majority of the class. All it does is open, into an XML document, the version of web.config in which the current Web page resides. Then it navigates to the <authorization> element and grabs all the <allow roles=""> elements. Finally, it places all the roles in an ArrayList to be grabbed by whoever needs them.
The last method, OnInit(), is an override method for the base class Page. First, it calls the base class’s method, and then it simply takes the roles and the current UserID and sends them to the AccountRoles database table-helper method, Authorization().
The key to the simplicity of this change is that the OnInit() is already called within the autogenerated code. This saves you from having to add this function call yourself (see Listing C).
AccountRoles database table
Basically, all the AccountRoles database (see Table A) does is store a list of all the roles that an account can have. AccountRoles is a very simple database table. All it contains is the user name, the role, and the date that the record was created.
AccountRoles authorization method
The final piece of the actual authorization process happens within the AccountRoles database helper-method, Authorization. Listing D shows how to select all roles from the AccountRoles database table.
At this point, you have all the roles allowed to see the Web page and all the roles that the user performs. All it takes is a simple intersection of the two to find out whether authorization should be granted. The code does this by trying to find a strings match between the two lists. When the first equality happens, the method leaves with a true value.
Note that the constructor for the AccountRoles database helper class, which takes the connection string out of the application-level web.config and creates a connection to the database, is not shown here. Listing D provides the code.
Hey, that was easy!
As you can see, adding role-based authorization to ASP.NET is a breeze. In fact, I think it should be internal to ASP.NET and not delegated to Windows and IIS as Microsoft has currently implemented it.