Membership with Windows Accounts...
By: Brian Mains
Date: April 25, 2006
Download the code.
Printer Friendly Version
The membership provider works really well for intranet and internet applications in how it validates the user
and manages roles. But I've personally had a need to be able to use windows accounts that have been assigned
application roles, as I don't have access to the domain and can't create windows roles to assign to all of my
users. There is a way to get the best of both of these, through some programmatic work. I won't go into an
overview of the Membership and Role providers; instead, I'm assuming you understand how these work.
In an intranet environment where you are using windows authentication, you can get the user ID through the Page's
User property, as such: Page.User.Identity.Name. This contains the user name plus domain for the currently
logged on user, and not the ASP.NET account. Using this, it is possible to interact with the Membership provider,
because this name should be unique for each user. The methods we will use are these:
Membership.CreateUser(string username, string password)
Membership.CreateUser(string username, string password, string email)
Membership.CreateUser(string username, string password, string email, string passwordquestion, string passwordanswer, bool isactivated, out MembershipCreateStatus status)
Membership.GetUser(string username)
Roles.AddUserToRole(string username, string roleName)
To make it easier, the code I used uses a custom page class, which inherits from System.Web.UI.Page. When the
user first enters the page (the initial page load), the membership provider gets the reference to the user. If
the user doesn't exist, it creates a new MembershipUser with the user’s properties, and by default grants
permission to the Users role (this example also has a Power Users and Administrators role). The code shown below
is defined in the Page.OnPreLoad method, at the PreLoad stage of the page lifecycle.
|
//Get the current user from the windows authentication
_user =Membership.GetUser(User.Identity.Name);
//If no user returned, then create a new user
if (_user == null)
{
MembershipCreateStatusstatus;
//Use the user name for the password; not going to be a problem because they don't use it
_user = Membership.CreateUser(User.Identity.Name, User.Identity.Name, "b@a.com", "q", "a", true, outstatus);
//If the status is not a success, as set by the reference variable
if (status != MembershipCreateStatus.Success)
throw new Exception("The creation failed due to the following status: " + status.ToString());
//Add user to the generic role
Roles.AddUserToRole(User.Identity.Name, "Users");
}
|
The code is pretty straightforward; on the initial page load (when page ispostback property is false), the user
object is retrieved. If, after retrieving the user, the object is null, then the user is created, with a dummy
email address, password question, and answer. In the windows world, this information isn’t needed anyway; as an
alternative I could setup the membership provider information in the web.config, which would disable the need for
it anyway; however, I did it this way for ease of use and to show you the longer CreateUser method, which has a
status variable. The status variable is an enumeration returned back to the caller with the status of the
account creation. If it failed, it will let you know why it failed, which can be used to give a specific reason
to the user.
The user will be added to the Users role by default, which I initially setup the roles using the Web Application
Administration tool that comes free with Visual Web Developer and Visual Studio 2005. The nice feature about
this setup is that all users that are created programmatically can be assigned to specific roles through this
tool as well. Opening up the project, selecting the security tab, and selecting Create or Manage Roles, you
see the following three roles I created.
Clicking on the power users Manage link, you go to the screen where you can select the user. I brought up the
users on my account, and by checking/unchecking the boxes, you can add/remove that user from the roles.
From this, it would be easy to create administrative pages to remove users and have other functionality. But as
you can see, it is easy to implement a membership feature, using windows accounts with application roles, with a
little extra work. The downside to this is that the user information is retrieved from the database each time.
As an alternative, the user information could be stored in the cache, and in the property, when the application
accesses the property, some other mechanism returns it; however, I'm using the database in this example.
|
//Accessible in any page that inherits this class
publicMembershipUser MembershipUser
{
get
{
//Could be replaced with cache or other alternative
if (_user == null)
_user = Membership.GetUser(User.Identity.Name);
return _user;
}
}
|
The page I attached to illustrate the example simply prints the user name, and the roles they belong to. It
retrieves the information from the database and writes it out directly, so you can see what is being output. It
also uses our new page variable to do this.
|
protectedvoid Page_Load(object sender, EventArgs e)
{
string name = this.MembershipUser.UserName;
this.lblMessage.Text = "User ID: " + name + "<br>Roles: ";
foreach (string role inRoles.GetRolesForUser(name))
this.lblMessage.Text += role + "<br>";
}
|
Switching roles for the user, you can then see the changes taking effect by refreshing or reloading the page.
And, with this custom page class, you can still access the original user information through the User property.
It's not very difficult at all to reuse the existing membership framework for alternative purposes.