True 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.
System.Web.UI.Page
replacement--AuthorizedPage
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.
Table A
|
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.