Rolling Your Own Website Administration Tool - Part 1By Dan Clem
Forms-based authentication combined with ASP.NET 2.0's Membership and Roles systems makes creating and managing user accounts incredibly easy. I continue to be amazed at how the login-related Web controls encapsulate the array of tasks that I had always had to code by hand in classic ASP. For more on the Membership and Roles systems, be sure to read the Examining ASP.NET 2.0's Membership, Roles, and Profiles article series.
To help administer users, roles, and authorization settings, ASP.NET 2.0 includes the Web
Site Administration Tool (WSAT). WSAT is available from the Visual Studio 2005 Website menu via the ASP.NET Configuration
menu option. Launching the WSAT from Visual Studio, however, allows only local websites to be administered.
Such restrictions are limiting when hosting a website remotely with a web hosting company. (Granted, the WSAT's files
are available in the
%WINDOWS%\Microsoft.NET\Framework\v2.0.50727\ASP.NETWebAdminFiles folder and can be
deployed from there.)
Rather than move the existing WSAT tool to my remote host, I decided to build my own WSAT-like tool from the ground up. My version duplicates all features inside the Security section of the WSAT and adds a useful "Access Rules Summary" view of the website security as applied to any given user or role. The complete code can be downloaded from the end of this article and added to your site within a matter of minutes. This article provides an overview of my custom WSAT implementation and explores the user list and add and edit user pages in detail. Part 2 explores the role management and access rules sections in detail. Read on to learn more!
Using My Custom Website Administration Tool
My complete customized WSAT application can be downloaded at the end of this article. The download includes a fully-functioning shell of a dummy corporate intranet. Its global navigation menu contains one link for each department - IT, marketing, sales, and so on - with each department's web pages existing as a separate, physical folder in the website. This demo uses the
SqlMembershipprovider, storing user information in the
ASPNETDB.MDFdatabase in the application's
App_Datafolder. This database is a Microsoft SQL Server 2005 Express Edition database.
Follow these steps to get up and running with this sample application:
- Copy the contents to the hard drive of your development machine, which must have both Visual Studio 2005 and SQL Server Express installed. The free Visual Web Developer version will work just fine.
- Open Visual Studio.
- Click File --> Open Web Site from the main menu, browse to the folder where you extracted the contents downloaded at the end of this article, and open up the website.
- Click the green arrow to start debugging. Visual Studio should start its built-in Web server and the login page should be displayed.
- Log in with user name "Dan Clem", password "dan" (omitting the quotation marks). Dan Clem is the only administrator in the system. You can log in as a non-administrator using any of the following user names: "Edward Eel", "Franklin Forester", "Gordy Gordon", "Harold Houdini", or "Ike Iverson". The password for each of these users is their first name, all lower case. Note that non-administrators are unable to visit the custom WSAT page.
- Click the Admin link from the global navigation menu to begin reviewing the application. The other links on the global navigation menu are simple placeholders for future development work on our dummy corporate intranet. They are used to demonstrate the Access Rule Management and Access Rule Summary pages.
- Copy the
adminfolder into your website's folder structure so that it exists directly underneath the root folder of your ASP.NET application. (In my application, I've mapped the ASP.NET application to the root website folder, but it should still work if your ASP.NET application is a subfolder inside the website.)
- Copy the
AlphalinksUser Control (
alphalinks.ascx) into a suitable spot inside your website, then modify the
@Registerdirective on the
users.aspxpage to match its new location. (For a more detailed discussion on configuring and working with User Controls, see An Extensive Examination of User Controls.)
- Copy the images found in the
ifolder to a suitable spot in your images folder, then modify the image links on the
- Make certain to register the following namespaces in the
system.websection of your web application's root
web.configfile. They are needed for the
DirectoryInfoclasses used by some of the web pages in the custom WSAT application:
<add namespace="System.Data" />
- You'll need to modify the pages to fit your master page and navigational menu techniques. (I use a hybrid ASP.NET 2.0/classic ASP approach, where the global navigation menu appears in a single master page that is shared throughout the site, while the secondary navigation menus appear as include files specific to each subfolder.)
- Note that I've split my
adminfolder into two subfolders:
activity. The custom WSAT application is fully contained inside the
accessfolder. I haven't yet developed the
activityfolder, but I intend to add web pages that provide a log of what users are viewing what pages.
- Secure the
adminfolder to the appropriate Roles or Users using the steps outlined in the "Securing Our Custom WSAT" section of this article.
Managing User Accounts
The Security section of the official ASP.NET 2.0 WSAT provides a set of pages for managing a website's users, roles, and access rules. In creating my custom WSAT application, I have rebuilt all of the core WSAT pages inside this section. Additionally, I added a useful "Access Rules Summary" page and other features that, in my opinion, improve the overall page flow and usability. I started out by building a set of user list pages that I felt would cover the needs of my typical deployments. I broke this out into separate pages for working with:
- Users by Name
- Users by Role
- Active Users
- Online Users
- Locked Out Users
Exploring the Users by Name View
In the Users by Name view the GridView is populated with the website's users via the following two lines of code:
I wanted to add an alphabetic filter to match the user interface found in the official WSAT. I decided to build this as an
ASP.NET User Control so that I could reuse it later. Because I'm just learning how to build ASP.NET controls, this task took a
bit longer than I planned, but I learned a couple things along the way, so allow me to share. I built two versions of
this User Control, which I've called
Alphalinks. Coming from classic ASP, I still have a strong bias toward the simplicity of
QueryString-based navigation, so that's how I built the first version of this control. The control simply outputted all
letters of the alphabet as regular links, adding a QueryString parameter in the form
&letter=X. This worked
great until I tried to use it alongside an ASP.NET
DropDownList control whose
was set to True. I soon realized that combining the ASP.NET postback and traditional QueryString-based navigation models
opens a can of worms.
With yet another lesson learned and yet another minor heartbreak behind me, I said goodbye to the QueryString-based
navigation model and built a new version as a proper postback-based ASP.NET User Control. I won't go into the details here,
but I quickly realized an advantage that comes with postback-based controls: we can access the control values as properties
rather than using the
Request.QueryString paradigm of the classic ASP world. In particular, I added a
Letter property to the
Alphalinks User Control that returned the selected letter. With this property
added, the control could be used programmatically, like so:
A Look at the Users by Role View
The Users by Role view uses a GridView to list the users that belong to a specified role. In place of the
AlphalinksUser Control, this page has a DropDownList that lists the roles in the system. This DropDownList is populated with the roles using the
GetAllRoles()method like so:
The filtering logic for this page is a trifle more complicated because there are no methods in the Membership or Roles sytems
that return the details for all users in a particular role. While the
Roles class does have a
method, it returns just the usernames of the users in the specified role and not the users' details like their email
address, active status, last logon date, and so forth. I overcame the lack of such a method by writing code that returns
all user details and then all users in a particular role. I then loop through the usernames in the specified role
and add the corresponding user details to a filtered collection.
The final three user-related pages (Active Users, Online Users, and Locked Out Users) were all straightforward. The
filtered lists were created by getting all user details via
Membership.GetAllUsers(), iterating through the
MembershipUsers collection, and checking the appropriate Boolean property of each
object in the collection to determine whether to add it to a filtered collection. This filtered collection was then
bound to the GridView on the web page. Note that "Active" corresponds to the
IsApproved property of the
MembershipUser class, "Online" to
and "Locked Out" to
|Alternative Approaches to Filtering Users|
The logic used to filter users by role and by active, online, and locked out status all work the same, in general. They get
all user details by calling |
For example, if you're using the
Creating New User Accounts
The Membership system makes it pretty easy to add new users via the
CreateUsermethod. My custom WSAT application contains an Add User page, which contains a CheckBoxList for Role selection followed by the expected form fields for the pertinent new user attributes.
When designing the Membership system, Microsoft decided to capture only essential user information, things like the user's name, their password, a comment about the user, their last login date, and so on. If we need to capture additional user-specific fields for our application - such as gender, address, date of birth, and so on - we can either use the Profile system or create our own infrastructure for storing this information. For more on ASP.NET 2.0's Profile system, see Profiles in ASP.NET 2.0; check out Erich Peterson's article, Customizing the CreateUserWizard Control for an example of storing additional user data in a custom table.
The following screen shot shows the Add User page in action:
The code to add a new user is simple: one line of code adds the user to the system; a second line then adds the comments
(because none of the
CreateUser method overloads includes a comments parameter). After the user has been added,
foreach loop associates the new user with each of the selected roles.
Editing Existing User Accounts
The Edit User page is based on the design of the Add User page and can be accessed from the various user list pages. I built this page using a CheckBoxList for the Roles and a DetailsView for the primary user info. Because the CheckBoxList is separate from the DetailsView control, I had to enable/disable the checkboxes manually to make them stay in sync with the built-in edit/view mode of the DetailsView:
I also had to write some code to add or remove the user from roles, as necessary. This code is called from the
OnItemUpdating event of the DetailsView.
This article provided an oview of my custom WSAT application (available for download at the end of this article), examining the user list pages and add and edit user pages in detail. The pages explored in this article make up the user management portion of the tool. There are also role management pages and web pages for specifying authorization rules. These topics are covered in Part 2.
Until then... Happy Programming!