O'Reilly logo

Visual C# 2005: A Developer's Notebook by Jesse Liberty

Stay ahead with the world's most comprehensive technology and business learning platform.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, tutorials, and more.

Start Free Trial

No credit card required

Add Roles to ASP.NET Accounts

You can assign a set of permissions to a group of people. You do so in two steps: first you assign permissions to a role, and then you assign users to the roles you've created. Any given user can be in more than one role (e.g., administrator and manager). The permissions you assign to each role can determine access to a page or can determine the content of a given page displayed to members of that role.

Note

Roles are named groups of permissions to which you can assign users.

How do I do that?

To demonstrate how to create roles and assign users to those roles, you'll need to create a new application, setting the appropriate IIS configuration. In the previous lab you created the directory for your application before you created the application itself. To see that you can create the relationship between physical and virtual directories in more than one way, this time let's reverse the order. Start by creating a new web application (called SecurityRoles).

Find the directory in which the Default.aspx page is held by clicking the page in the Solution Explorer and looking at the properties window. Use the IIS Administrator to create a virtual directory called SecurityRoles that points to that physical directory. Right-click the virtual directory and select Properties.

Click the ASP.NET tab and the Edit Configuration button (as you did in the previous lab). Once again click the Authentication tab and set Forms Authentication, but this time be sure to check the "Role management enabled" checkbox, as shown in Figure 4-21.

Checking role management

Figure 4-21. Checking role management

When you click OK and close the configuration dialogs, you'll find that a Web.config file has been added to the directory:

<?xml version="1.0"?>
<configuration>
   <connectionStrings>
  <remove name="LocalSqlServer" />
  <add name="LocalSqlServer" connectionString="data source=.\sqlexpress;Integrated 
Security=SSPI;Initial Catalog=aspnetdb" />
 </connectionStrings>
 <system.web>
      <membership defaultProvider="AspNetSqlMembershipProvider" />
  <authentication mode="Forms"/>
      <roleManager enabled="True" defaultProvider="AspNetSqlRoleProvider" />
      <compilation debug="true"/></system.web>
</configuration>

Notice that this time, the roleManager element has been added and its enabled attribute has been set to true.

Now you need to add to this lab the pages from the previous lab.

Tip

If you skipped the previous lab, simply download the source code and use the files in the directory marked FormsBasedSecurity.

One way to add these pages is to copy the .aspx and .aspx.cs files (that is all the files except Web.config) to the new directory.

Once you've done this, return to Visual Studio 2005 and, in the Solution Explorer, right-click the project and choose Add Existing Items to add the pages from the earlier lab to this one. Now you are set to add roles to this project.

Tip

A potentially easier way to copy your web site is to use the new Website Copy Website command. This opens a wizard that allows you to specify which files to copy to the new web site. This is demonstrated in the next lab.

Add two HyperLink controls to the default page. The first link should contain the words Add User and the second link should contain the words Manage Roles. The first link will redirect the user to the AddUser page you imported (set NavigateUrl by clicking the ellipses and selecting the CreateAccount.aspx page). Go to AddUser.aspx and change the ContinueDestinationPageURL property of the CreateUserWizard control to the default page so that each time you add a user you will be brought back to the Default.aspx page.

Create a new ManageRoles.aspx page. This page has a somewhat complex layout because it must display the list of roles and the list of users supported by your site, as well as which users have been assigned which roles. The complete .aspx listing is shown in Example 4-1, though it might be easier to download this code from either the O'Reilly or Liberty Associates web site.

Tip

Go back to Default.aspx and set ContinueDestinationPageURL for the second hyperlink to this new page.

Example 4-1. The ManageRoles.aspx page

<%@ Page Language="C#" AutoEventWireup="true" 
CodeFile="ManageRoles.aspx.cs" Inherits="ManageRoles_aspx" %>
    
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/
DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
    <title>Manage Roles</title>
</head>
<body>
    <form id="form1" runat="server">
  <h3>Role Membership
      <asp:HyperLink ID="linkHome" Runat="server" NavigateUrl="~/Default.aspx">
Home page</asp:HyperLink>
  </h3>
  <asp:Label id="Msg" ForeColor="maroon" runat="server" /><BR>
  <table CellPadding="3" border="0">
    <tr>
      <td valign="top">Roles:</td>
      <td valign="top" style="width: 186px"><asp:ListBox id="RolesListBox" 
            runat="server" Rows="8" AutoPostBack="True">
      </asp:ListBox></td>
      <td valign="top">Users:</td>
      <td valign="top"><asp:ListBox id="UsersListBox" DataTextField="Username" 
         Rows="8" SelectionMode="Multiple" runat="server" /></td>
      <td valign="top" visible="false">
            <table>
            <tr>
                <td>
                    <asp:Button Text="Add User(s) to Role" id="btnAddUsersToRole"
                    runat="server" OnClick="AddUsers_OnClick" />
                </td>            
            </tr>
            <tr>
                <td>          
                    <asp:Button Text="Create new Role" id="btnCreateRole"
                    runat="server" OnClick="CreateRole_OnClick" 
                    Width="170px" Height="24px" />
                </td>
            </tr>
            <tr>
            <td>
          <asp:Panel ID="pnlCreateRole" Runat="server" Width="259px" 
            Height="79px" Visible="False" BackColor="#E0E0E0">
              <br />
              &nbsp;&nbsp;
              <asp:Label ID="Label2" Runat="server" Text="New Role:" 
                Width="72px" Height="19px"/>
              <asp:TextBox ID="txtNewRole" Runat="server"/>&nbsp;<br />
              &nbsp;&nbsp;<br />
              &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
              &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
              <asp:Button ID="btnAddRole" Runat="server" 
                  Text="Add" OnClick="btnAddRole_Click"
                  Width="64px" Height="24px" /><br />
          </asp:Panel>
            
            </td>
            </tr>
            </table>
      </td>
    </tr>
    <tr>
      <td valign="top">Users In Role:</td>
      <td valign="top" style="width: 186px">
            <asp:GridView runat="server" CellPadding="4" id="UsersInRoleGrid" 
                                   AutoGenerateColumns="false" Gridlines="None" 
                                   CellSpacing="0" 
            OnRowCommand="UsersInRoleGrid_RemoveFromRole">
                      <HeaderStyle BackColor="navy" ForeColor="white" />
                      <Columns>
                        <asp:TemplateField HeaderText="User Name">
                          <ItemTemplate>
                            <%# Container.DataItem.ToString( ) %>
                          </ItemTemplate>
                        </asp:TemplateField>
                        <asp:ButtonField Text="Remove From Role"  ButtonType="Link" />
                      </Columns>
            </asp:GridView>
       </td>
    </tr>
  </table>    
  </form>
</body>
</html>

Tip

This page is designed to be useful, not pretty. It is based on a demonstration .aspx page provided by Microsoft with beta software.

The complete code associated with the ManageRoles.aspx page is listed in Example 4-2.

Example 4-2. The complete ManageRoles.aspx code

using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
    
public partial class ManageRoles_aspx : System.Web.UI.Page
{
   string[  ] rolesArray;
   MembershipUserCollection users;
   string[  ] usersInRole;
    
   public void Page_Load( )
   {
      Msg.Text = "";
    
    
      if (!IsPostBack)
      {
         rolesArray = Roles.GetAllRoles( );
         RolesListBox.DataSource = rolesArray;
         RolesListBox.DataBind( );
    
         // Bind users to ListBox.
    
         users = Membership.GetAllUsers( );
         UsersListBox.DataSource = users;
         UsersListBox.DataBind( );
      }
    
      if (RolesListBox.SelectedItem != null)
      {
         // Show users in role. Bind user list to GridView.
    
         usersInRole = Roles.GetUsersInRole(RolesListBox.SelectedItem.Value);
         UsersInRoleGrid.DataSource = usersInRole;
         UsersInRoleGrid.DataBind( );
      }
   }
    
   // void AddUsersButton_Click(object sender, EventArgs e)
    
   public void AddUsers_OnClick(object sender, EventArgs args)
                  {
                  // Verify that a role is selected.

      if (RolesListBox.SelectedItem =  = null)
                  {
                  Msg.Text = "Please select a role.";
                  return;
                  }

                  // Verify that at least one user is selected.

      if (UsersListBox.SelectedItem =  = null)
                  {
                  Msg.Text = "Please select one or more users.";
                  return;
                  }

                  // Create list of users to be added to the selected role.

      string[  ] newusers = new string[UsersListBox.GetSelectedIndices( ).Length];

                  for (int i = 0; i < newusers.Length; i++)
                  {
                  newusers[i] = 
                  UsersListBox.Items[UsersListBox.GetSelectedIndices( )[i]].Value;
                  }
   
    
      // Add the users to the selected role.
    
      try
      {
         Roles.AddUsersToRole(newusers, RolesListBox.SelectedItem.Value);
    
         // Re-bind users in role to GridView.
    
         usersInRole = Roles.GetUsersInRole(RolesListBox.SelectedItem.Value);
         UsersInRoleGrid.DataSource = usersInRole;
         UsersInRoleGrid.DataBind( );
      }
      catch (HttpException e)
      {
         Msg.Text = e.Message;
      }
   }
    
    
   public void UsersInRoleGrid_RemoveFromRole(object sender, GridViewCommandEventArgs 
args)
   {
      // Get the selected username to remove.
    
      int index = Convert.ToInt32(args.CommandArgument);
    
      string username = ((DataBoundLiteralControl)UsersInRoleGrid.Rows[index].
Cells[0].Controls[0]).Text;
    
    
      // Remove the user from the selected role.
    
      try
      {
         Roles.RemoveUserFromRole(username, RolesListBox.SelectedItem.Value);
      }
      catch (Exception e)
      {
         Msg.Text = "An exception of type " + e.GetType( ).ToString( ) +
                " was encountered removing the user from the role.";
      }
    
    
      // Re-bind users in role to GridView.
    
      usersInRole = Roles.GetUsersInRole(RolesListBox.SelectedItem.Value);
      UsersInRoleGrid.DataSource = usersInRole;
      UsersInRoleGrid.DataBind( );
   }
   public void CreateRole_OnClick(object sender, EventArgs e)
                  {
                  pnlCreateRole.Visible = true;
                  }
   /// <summary>
   /// Handles clicking the Add button in the panel made
   /// visible by clicking Create New Role
   /// </summary>
   public void btnAddRole_Click(object sender, EventArgs e)
   {
      // make sure you have some text in the name of the role
      if (txtNewRole.Text.Length > 0)
      {
         string newRole = txtNewRole.Text;
    
         // if the role does not already exist, add it
         // rebind the RolesListBox to show the new role
         if (Roles.RoleExists(newRole) =  = false)
         {
            Roles.CreateRole(newRole);
            rolesArray = Roles.GetAllRoles( );
            RolesListBox.DataSource = rolesArray;
            RolesListBox.DataBind( );
         }
      }
    
      pnlCreateRole.Visible = false;
   }
}

What just happened?

Here's how the code works. The logic begins with the Create Role button's onClick event handler, which makes the Create Role panel visible:

void CreateRole_OnClick(object sender, EventArgs e)
{
   pnlCreateRole.Visible = true;
}

The panel contains a text box (New Role) that you use to name a new role, and a button (Add) to add the new role to the roles collection, as shown in Figure 4-22.

The New Role panel

Figure 4-22. The New Role panel

When you click the Add button, the btnAddRole_Click event handler is called:

void btnAddRole_Click(object sender, EventArgs e)
{
   if (txtNewRole.Text.Length > 0)
   {
      string newRole = txtNewRole.Text;
    
      if (Roles.RoleExists(newRole) =  = false)
      {
         Roles.CreateRole(newRole);
               rolesArray = Roles.GetAllRoles( );
               RolesListBox.DataSource = rolesArray;
               RolesListBox.DataBind( );
      }
   }

Assuming there is text in the New Role text box, you check whether the role already exists; if it doesn't you create a new role using the static CreateRole method of the Roles class provided by .NET 2.0.

Then you get all the roles and rebind the listbox, which now will include the new role, as shown in Figure 4-23.

The Roles listbox

Figure 4-23. The Roles listbox

Once the new role is added, the panel is closed:

pnlCreateRole.Visible = false;

Run the application. If you are starting with a new database add some users. Next, click Add Roles and add a couple of roles. Then click a role (to highlight it) and one or more users (to highlight them), and then click Add User(s) to Role. This invokes the AddUsers_OnClick event handler.

First you check to make sure a role has been selected:

if (RolesListBox.SelectedItem =  = null)
{
   Msg.Text = "Please select a role.";
   return;
}

and that at least one user has been selected:

if (UsersListBox.SelectedItem =  = null)
{
   Msg.Text = "Please select one or more users.";
   return;
}

Then you get an array of the users to be added:

      string[  ] newusers = new string[UsersListBox.GetSelectedIndices( ).Length];

and you iterate through those users, retrieving each selected user's name:

      for (int i = 0; i < newusers.Length; i++)
      {
         newusers[i] = UsersListBox.Items[
           UsersListBox.GetSelectedIndices( )[i]].Value;
      }

Now you call the static AddUsersToRole method on the Roles class, passing in the array of usernames and the role you want these users added to. Then you rebind the users who are in that role to the UsersInRoleGrid method:

try
{
   Roles.AddUsersToRole(newusers, RolesListBox.SelectedItem.Value);
    
   // Re-bind users in role to GridView.
    
   usersInRole = Roles.GetUsersInRole(RolesListBox.SelectedItem.Value);
   UsersInRoleGrid.DataSource = usersInRole;
   UsersInRoleGrid.DataBind( );
}
catch (HttpException e)
{
   Msg.Text = e.Message;
}

The results are shown in Figure 4-24.

Adding users to roles

Figure 4-24. Adding users to roles

Add each user to one or more roles, and when you are done you'll be ready to test whether these roles have any effect. To do so, stop the application and edit the default page. Click the smart tag for the LoginView control and click Edit RoleGroups, as shown in Figure 4-25. This will open the RoleGroup Collection Editor dialog box.

Clicking Edit RoleGroups

Figure 4-25. Clicking Edit RoleGroups

Add a couple of the roles you created earlier, as shown in Figure 4-26.

The RoleGroup Collection Editor

Figure 4-26. The RoleGroup Collection Editor

Switch to Source view on your Default.aspx page; a new section has been added to the LoginView control:

<asp:LoginView ID="LoginView1" Runat="server">
    <RoleGroups>
        <asp:RoleGroup Roles="Manager"></asp:RoleGroup>
        <asp:RoleGroup Roles="Supervisor"></asp:RoleGroup>
    </RoleGroups>

Now you can control what the members of each role will see by using contentTemplate elements. You add these between the opening and closing tags of each role:

<RoleGroups>
    <asp:RoleGroup Roles="Manager">
       <ContentTemplate>
         Welcome
         <asp:LoginName ID="LoginNameManager" Runat="server" />
         You are a manager
       </ContentTemplate>
    </asp:RoleGroup>
    <asp:RoleGroup Roles="Supervisor">
        <ContentTemplate>
            Supervisor tools go here
        </ContentTemplate>
    </asp:RoleGroup>
</RoleGroups>

Run the application. In the preceding example, I added josborn and sliberty to the Supervisor role, but not jliberty, who is in the Manager role. When I log in as josborn I see the words "Supervisor tools go here," but if I log in as jliberty I do not see those words. Instead, I see the words dictated by the content template associated with managers.

What about . . .

...restricting access to pages based on roles? Can I do that?

Yes, you can test if the logged-in user is in a particular role by using the User.IsInRole method:

bool isManager = User.IsInRole("Manager");

You can also restrict access by adding an authorization section to a Web.config file (which you can place in a subdirectory to control access to all files in that subdirectory and to all of its subdirectories), and you can use the location element to control access to specific files:

<authorization>
  <deny users='?' />
  <allow roles='Manager' />
  <deny users='*' />
</authorization>

The first line (deny users='?') prohibits access to anyone who is not logged in. The second line (allow roles='Manager') allows access to anyone in the Manager role, and the final line (deny users='*') disallows anyone, but is overridden by allow roles.

...what about using the ASP.NET Web Site Administration Tool to set up roles?

Sure! First you need to stop the application. Then, on the Visual Studio menu bar, click Website ASP.NET Configuration and choose the Security tab. Click "Enable roles," as shown in Figure 4-27.

Enabling roles through the ASP.NET Web Site Administration Tool

Figure 4-27. Enabling roles through the ASP.NET Web Site Administration Tool

Where can I learn more?

MSDN offers a good article on membership, titled "New Membership Features in ASP.NET Whidbey." Also, see my article on roles, titled "ASP.NET Forms Security Part 2" and available on O'Reilly's ONDotnet.com site at http://www.ondotnet.com. You'll also find an excellent article on roles and ASP.NET 2.0 security by Alex Homer, Rob Howard, and David Sussman at http://www.informit.com/articles/article.asp?p=351414&seqNum=3.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, interactive tutorials, and more.

Start Free Trial

No credit card required