Role-Based Authorization With Forms AuthenticationBy Darren Neimke and Scott Mitchell
|For More Information...|
For more information on forms-based authentication in ASP.NET be sure to read Dissecting Forms-Based Authentication.
This article was written in 2003 and is applicable to ASP.NET version 1.x. Starting with ASP.NET version 2.0, Microsoft introduced the Membership and Roles frameworks, which greatly simplify creating and managing user accounts and roles. Refer to Examining ASP.NET's Membership, Roles, and Profile and these Security Tutorials for more information on using Membership and Roles.
In Web applications, typically there exist certain parts of the site that only certain individuals, or groups of individuals, can access. For example, imagine an intranet Web site used to administer the content on a company's public Internet Web site, where the public Web site lists products sold by the company. From the administrative site, all company employees might be able to make minor changes to the products' descriptions, quantity, and other such non-essential information. However, perhaps only a subset of trusted employees might be able to change the products' prices. And even a smaller subset of employees would be able to add new products or delete existing products from the database.
To handle such a hierarchy of capabilities, a traditional security model to use is to divide users into roles, and then to assign permissions to various resources on a role-by-role basis. For example, our fictional company's administrative Web site might be setup so that the President, CEO, and CIO are made "Administrators" of the product database, and have access to change the product database via the online interface in any way they desire. The top-level managers might be added to the Price Changer role, meaning they can change the prices of existing products, while all other company employees were inserted into the Minor Updates role. Such a security model is typically referred to a role-based authorization model, as the authorization users enjoy is based upon the role they play within the system.
In this article we will examine how to utilize role-based authorization in an ASP.NET Web application using Forms authentication. Specifically, we'll examine the data model needed for implementing roles, we'll see how to determine what roles a given user belongs to, and then how to restrict (or grant) access to resources based on a user's roles.
A Quick Security Overview
When thinking or talking about security, there are two fundamental underpinnings which are central to understanding role-based authorization and security models in general. These two concepts are:
- Authentication - authentication is the act of identifying who a user is. In Web applications, this is typically done by having the user provide some credentials, such as a username and password.
- Authorization - authorization is the act of granting or denying access to a resource based upon the user attempting to access the resource.
Before we can discuss role-based authorization, we must first think about how we will authenticate our users. ASP.NET provides three methods for authentication:
- Windows Authentication - Useful when working on an intranet, where every user who needs to be authenticated has a Windows account on the Web server's domain,
- Passport Authentication - Uses Microsoft's Passport service, and
- Forms Authentication - Prompts the user for a set of credentials (typically username and password).
This article will focus on using role-based authorization with Forms authentication. (If you are unfamiliar with Forms authentication, be sure to check out Darren Neimke's excellent article, Using Forms Authentication in ASP.NET.)
Getting Role-Based Authorization Working - the First Steps
In order to provide role-based authorization, we need some way to model the roles and the users that participate in these roles. Typically, when using Forms authentication a user is modeled as a row in a database table. Each user usually contains information pertinent to the Web application, including the user's credentials (i.e., their username and password).
So, before we can get started at looking at the code necessary for implementing role-based authorization, we need to provide a data model. Our data model will consist of three related tables:
Users- each record in this table models an individual user. The pertinent fields in this table include
UserID(a unique identifier for each user),
Groups- each record in this table models a group. The
Groupstable's pertinent fields are
Name. Groups are the classifications to which users can be assigned. For example, a Web application might have groups like: Administrators, Moderators, Testers, and so on.
Rolestable models the many-to-many relationship between
Groups. Specifically, a role maps a user to a group. The
Rolestable needs only two fields:
An example database might be as follows:
In this sample database there are five users and four groups. Bob is in the Administrator role, Scott is in the Moderators and Testers roles, Jisun is in the Premium Members role, Sam is in the Testers and Premium Members roles, and John is not in any roles.
Determining What Roles a User Is In
The .NET Framework contains an
HttpApplicationclass that represents an ASP.NET Web application. This class has a number of events that can fire during various times of the Web application's lifecycle. The invent we're interested in is the
AuthenticateRequestevent, which fires each time when the ASP.NET security module has established the identity of a user. We can write an event handler for this event in the
Global.asaxfile. In this event handler we need to determine what roles this user belongs to.
The following shows the code for the
AuthenticateRequest event handler:
Let's examine this code sample line-by-line. The first line checks to see if the user is an authenticated user. That is, if we are dealing with an anonymous Web user, there's no point in hitting the database to determine what roles the anonymous user belongs to. By the data model I presented earlier, only users that exist in the database can be assigned roles.
If the user has been authenticated, then the
will return True, and the code inside the
If statement will execute.
Next, the code uses the Microsoft Data Access Application Block to execute the stored
rolesForUser, passing in the authenticated user's
name as the value for the
@Username parameter. (If you are unfamiliar
with the MS Data Access Application Block, it is a free assembly from Microsoft that
can be used to encapsulate a lot of the extra complexity involved in making
database calls. For more information, be sure to read:
Examining the Data Access Application Block.)
The results of the stored procedure - whose syntax we'll examine shortly - are then
inserted into an ArrayList. The ArrayList is then converted into a String array using
ToArray() method. Finally, the current user's
is reassigned to a new
GenericPrincipal instance with the user's existing
Identity and the set of roles. (Don't worry if you do not yet understand
the syntax here or the purpose of the code - we'll discuss this last line of code in
more detail in the next section.)
rolesForUser stored procedure is fairly straightforward - it simply
takes in a single parameter (the username to search on) and then returns the list of
roles the user belongs to.
In Part 2 we'll examine the code for this
event handler in more detail, specifically examining the
class and Principals, Roles, Groups, and Users!