共用方式為


將角色指派給使用者 (C#)

作者:Scott Mitchell

注意

本文撰寫之後,ASP.NET 成員資格提供者已被 ASP.NET 身分識別取代。 強烈建議您將應用程式更新為使用 ASP.NET 身分識別 平臺,而不是本文撰寫時精選的成員資格提供者。 ASP.NET 身分識別的一些優點優於 ASP.NET 成員資格系統,包括 :

  • 更好的效能
  • 改善擴充性和可測試性
  • 支援 OAuth、OpenID Connect 和雙因素驗證
  • 宣告型身分識別支援
  • 與 ASP.Net Core 的較佳互通性

下載程式代碼下載 PDF

在本教學課程中,我們將建置兩個 ASP.NET 網頁,以協助管理哪些使用者屬於哪些角色。 第一頁將包含功能,以查看哪些使用者屬於指定角色、特定使用者所屬的角色,以及從特定角色指派或移除特定使用者的能力。 在第二個頁面中,我們將增強 CreateUserWizard 控制項,使其包含指定新建立使用者所屬角色的步驟。 這在系統管理員能夠建立新使用者帳戶的案例中很有用。

簡介

上一個教學 課程會檢查角色架構和 SqlRoleProvider ;我們已瞭解如何使用 Roles 類別來建立、擷取和刪除角色。 除了建立和刪除角色之外,我們必須能夠指派或移除角色中的使用者。 不幸的是,ASP.NET 不會隨附任何 Web 控制項來管理哪些使用者屬於哪些角色。 相反地,我們必須建立自己的 ASP.NET 網頁來管理這些關聯。 好消息是將使用者新增和移除至角色相當容易。 類別 Roles 包含許多方法,可將一或多個使用者新增至一或多個角色。

在本教學課程中,我們將建置兩個 ASP.NET 網頁,以協助管理哪些使用者屬於哪些角色。 第一頁將包含功能,以查看哪些使用者屬於指定角色、特定使用者所屬的角色,以及從特定角色指派或移除特定使用者的能力。 在第二個頁面中,我們將增強 CreateUserWizard 控制項,使其包含指定新建立使用者所屬角色的步驟。 這在系統管理員能夠建立新使用者帳戶的案例中很有用。

現在就開始吧!

列出哪些使用者屬於哪些角色

本教學課程的第一個商務順序是建立網頁,讓使用者可以指派給角色。 在我們擔心如何將使用者指派給角色之前,讓我們先專注于如何判斷哪些使用者屬於哪些角色。 有兩種方式可以顯示這項資訊:「依角色」或「依使用者」。我們可以允許訪客選取角色,然後向使用者顯示屬於角色的所有使用者, (「依角色」顯示) ,或者我們可以提示訪客選取使用者,然後向使用者顯示指派給該使用者的角色, (「依使用者」顯示) 。

在訪客想要知道屬於特定角色的使用者集的情況下,「依角色」檢視很有用;當訪客需要知道特定使用者的角色 () 時,「依使用者」檢視很理想。 讓我們的頁面同時包含「依角色」和「依使用者」介面。

我們將從建立「依使用者」介面開始。 此介面包含下拉式清單和核取方塊清單。 下拉式清單將會填入系統中的一組使用者;核取方塊會列舉角色。 從下拉式清單中選取使用者將會檢查使用者所屬的角色。 流覽頁面的人員接著可以核取或取消核取核取方塊,以從對應的角色新增或移除選取的使用者。

注意

使用下拉式清單來列出使用者帳戶不是有數百個使用者帳戶的網站的理想選擇。 下拉式清單的設計目的是允許使用者從相對短的選項清單中挑選一個專案。 隨著清單專案的數目成長,它很快就會變得不輕鬆。 如果您要建置可能有大量使用者帳戶的網站,建議您考慮使用替代的使用者介面,例如可分頁的 GridView 或列出可篩選的介面,提示訪客選擇信件,然後只顯示使用者名稱開頭為所選字母的使用者。

步驟 1:建置「依使用者」使用者介面

UsersAndRoles.aspx開啟頁面。 在頁面頂端,新增名為 的 ActionStatus 標籤 Web 控制項,並清除其 Text 屬性。 我們將使用此標籤來提供所執行動作的意見反應,顯示「使用者 Tito 已新增至系統管理員角色」或「使用者 Jisun 已從監督員角色中移除」等訊息。若要讓這些訊息成為醒目提示,請將 Label 的 CssClass 屬性設定為 「重要」。

<p align="center"> 

     <asp:Label ID="ActionStatus" runat="server" CssClass="Important"></asp:Label> 
</p>

接下來,將下列 CSS 類別定義新增至 Styles.css 樣式表單:

.Important 
{ 
     font-size: large; 
     color: Red; 
}

此 CSS 定義會指示瀏覽器使用大型紅色字型來顯示標籤。 圖 1 透過 Visual Studio Designer顯示此效果。

標籤的 CssClass 屬性會產生大型、紅色字型

圖 1:標籤 CssClass 的屬性會產生大型、紅色字型 (按一下以檢視大小完整的影像)

接下來,將 DropDownList 新增至頁面、將其 ID 屬性設定為 UserList ,並將其屬性設定 AutoPostBack 為 True。 我們將使用此 DropDownList 列出系統中的所有使用者。 這個 DropDownList 將會系結至 MembershipUser 物件的集合。 由於我們想要 DropDownList 顯示 MembershipUser 物件的 UserName 屬性 (,並使用它做為清單專案的值) ,請將 DropDownList 的 DataTextFieldDataValueField 屬性設定為 「UserName」。

在 DropDownList 底下,新增名為 的 UsersRoleList Repeater。 此重複程式會將系統中的所有角色列為一系列核取方塊。 使用下列宣告式標記定義 Repeater 的 ItemTemplate

<asp:Repeater ID="UsersRoleList" runat="server"> 
     <ItemTemplate> 
          <asp:CheckBox runat="server" ID="RoleCheckBox" AutoPostBack="true" 

               Text='<%# Container.DataItem %>' /> 
          <br /> 
     </ItemTemplate> 
</asp:Repeater>

標記 ItemTemplate 包含名為 RoleCheckBox 的單一 CheckBox Web 控制項。 CheckBox 的 AutoPostBack 屬性設定為 True,且 Text 屬性系結至 Container.DataItem 。 資料系結語法的原因是 Container.DataItem 角色架構會以字串陣列的形式傳回角色名稱清單,而這是我們將系結至 Repeater 的這個字串陣列。 此語法為何用來顯示系結至資料 Web 控制項之陣列內容的完整描述,已超出本教學課程的範圍。 如需有關此問題的詳細資訊,請參閱將 純量陣列系結至資料 Web 控制項

此時,您的「依使用者」介面宣告式標記看起來應該類似下列內容:

<h3>Manage Roles By User</h3> 

<p> 
     <b>Select a User:</b> 
     <asp:DropDownList ID="UserList" runat="server" AutoPostBack="True" 
          DataTextField="UserName" DataValueField="UserName"> 

     </asp:DropDownList> 
</p> 
<p> 
     <asp:Repeater ID="UsersRoleList" runat="server"> 
          <ItemTemplate> 
               <asp:CheckBox runat="server" ID="RoleCheckBox" AutoPostBack="true" 

                    Text='<%# Container.DataItem %>' /> 
               <br /> 
          </ItemTemplate> 
     </asp:Repeater> 
</p>

我們現在已準備好撰寫程式碼,將使用者帳戶集系結至 DropDownList,並將角色集系結至 Repeater。 在頁面的程式碼後置類別中,使用下列程式碼新增名為 BindUsersToUserList 和另一個名為 BindRolesList 的方法:

private void BindUsersToUserList() 
{ 
     // Get all of the user accounts 
     MembershipUserCollection users = Membership.GetAllUsers(); 
     UserList.DataSource = users; 
     UserList.DataBind(); 
}
 
private void BindRolesToList() 
{ 
     // Get all of the roles 
     string[] roles = Roles.GetAllRoles(); 
     UsersRoleList.DataSource = roles; 
     UsersRoleList.DataBind(); 
}

方法會 BindUsersToUserList 透過Membership.GetAllUsers 方法擷取系統中的所有使用者帳戶。 這會傳回物件 MembershipUserCollection,這是 實例的MembershipUser集合。 此集合接著會系結至 UserList DropDownList。 MembershipUser建立集合的實例包含各種屬性,例如 UserNameEmailCreationDateIsOnline 。 若要指示 DropDownList 顯示內容的值 UserName ,請確定 UserList DropDownList 的 DataTextFieldDataValueField 屬性已設定為 「UserName」。

注意

方法 Membership.GetAllUsers 有兩個多載:一個不接受任何輸入參數並傳回所有使用者,另一個接受頁面索引和頁面大小的整數值,只傳回使用者的指定子集。 當可分頁的使用者介面元素中顯示大量的使用者帳戶時,第二個多載可用來更有效率地透過使用者頁面,因為它只會傳回使用者帳戶的精確子集,而不是全部。

方法 BindRolesToList 會從呼叫 Roles 類別GetAllRoles 方法開始,這個方法會傳回字串陣列,其中包含系統中的角色。 此字串陣列接著會系結至 Repeater。

最後,當第一次載入頁面時,我們需要呼叫這兩種方法。 將下列程式碼加入至 Page_Load 事件處理常式:

protected void Page_Load(object sender, EventArgs e) 
{ 
     if (!Page.IsPostBack) 
     { 
          // Bind the users and roles 
          BindUsersToUserList(); 
          BindRolesToList(); 
     } 
}

在此程式碼就緒後,請花點時間流覽網頁流覽瀏覽器;您的畫面看起來應該類似圖 2。 所有使用者帳戶都會填入下拉式清單中,然後在該清單中,每個角色都會顯示為核取方塊。 由於我們將 DropDownList 和 CheckBox 的內容設定 AutoPostBack 為 True,因此變更選取的使用者或檢查或取消核取角色會導致回傳。 不過,由於我們尚未撰寫程式碼來處理這些動作,所以不會執行任何動作。 我們將在後續兩節中處理這些工作。

頁面會顯示使用者和角色

圖 2:頁面會顯示 [使用者和角色] (按一下以檢視大小完整的影像)

檢查所選使用者所屬的角色

第一次載入頁面時,或每當訪客從下拉式清單中選取新使用者時,我們需要更新 UsersRoleList 的核取方塊,以便只有在選取的使用者屬於該角色時,才會核取指定的角色核取方塊。 若要完成這項作業,請使用下列程式碼建立名為 CheckRolesForSelectedUser 的方法:

private void CheckRolesForSelectedUser() 
{ 
     // Determine what roles the selected user belongs to 
     string selectedUserName = UserList.SelectedValue; 
     string[] selectedUsersRoles = Roles.GetRolesForUser(selectedUserName); 

     // Loop through the Repeater's Items and check or uncheck the checkbox as needed 

     foreach (RepeaterItem ri in UsersRoleList.Items) 
     { 
          // Programmatically reference the CheckBox 
          CheckBox RoleCheckBox = ri.FindControl("RoleCheckBox") as CheckBox; 
          // See if RoleCheckBox.Text is in selectedUsersRoles 
          if (selectedUsersRoles.Contains<string>(RoleCheckBox.Text)) 
               RoleCheckBox.Checked = true; 
          else 
               RoleCheckBox.Checked = false; 
     } 
}

上述程式碼會從判斷選取的使用者身分開始。 然後,它會使用 Roles 類別GetRolesForUser(userName) 的 方法,將指定的使用者角色集當做字串陣列傳回。 接下來,會列舉重複項的專案,而且會以程式設計方式參考每個專案的 RoleCheckBox CheckBox。 只有在它對應的角色包含在字串陣列中 selectedUsersRoles 時,才會檢查 CheckBox。

注意

如果您使用 ASP.NET 2.0 版,則 selectedUserRoles.Contains<string>(...) 語法將不會編譯。 方法是LINQ連結 Contains<string> 庫的一部分,這是 ASP.NET 3.5 的新功能。 如果您仍在使用 ASP.NET 2.0 版,請改用Array.IndexOf<string> 方法

CheckRolesForSelectedUser 兩種情況下必須呼叫 方法:第一次載入頁面時,以及每當 UserList DropDownList 選取的索引變更時。 因此,在 呼叫 BindUsersToUserListBindRolesToList) 之後,從 Page_Load 事件處理常式呼叫這個方法 (。 此外,請為 DropDownList 的事件 SelectedIndexChanged 建立事件處理常式,並從該處呼叫此方法。

protected void Page_Load(object sender, EventArgs e) 
{ 
     if (!Page.IsPostBack) 
     { 

          // Bind the users and roles 
          BindUsersToUserList(); 
          BindRolesToList(); 
          // Check the selected user's roles 
          CheckRolesForSelectedUser(); 
     } 
} 

... 

protected void UserList_SelectedIndexChanged(object sender, EventArgs e) 
{ 
     CheckRolesForSelectedUser(); 
}

有了此程式碼,您可以透過瀏覽器測試頁面。 不過,由於 UsersAndRoles.aspx 頁面目前缺少將使用者指派給角色的能力,因此沒有任何使用者擁有角色。 我們會在一段時間建立將使用者指派給角色的介面,讓您可以接受此程式碼運作的字組,並稍後驗證它是否正常運作,或者您可以將記錄 aspnet_UsersInRoles 插入資料表,以手動將使用者新增至角色,以便立即測試這項功能。

從角色指派和移除使用者

當訪客在重複程式中檢查或取消核取 CheckBox UsersRoleList 時,我們需要從對應的角色新增或移除選取的使用者。 CheckBox 的 AutoPostBack 屬性目前設定為 True,每當檢查或取消核取 Repeater 中的 CheckBox 時,就會造成回傳。 簡單來說,我們需要建立 CheckBox 事件的 CheckChanged 事件處理常式。 由於 CheckBox 位於 Repeater 控制項中,因此我們需要手動新增事件處理常式管線。 首先,將事件處理常式新增至程式碼後置類別做為 protected 方法,如下所示:

protected void RoleCheckBox_CheckChanged(object sender, EventArgs e) 
{ 

}

我們將會返回撰寫此事件處理常式的程式碼。 但首先讓我們完成事件處理管線。 從 Repeater 的 ItemTemplate 中的 CheckBox 新增 OnCheckedChanged="RoleCheckBox_CheckChanged" 。 此語法會將 RoleCheckBox_CheckChanged 事件處理常式連線至 RoleCheckBoxCheckedChanged 事件。

<asp:CheckBox runat="server" ID="RoleCheckBox" 
     AutoPostBack="true" 
     Text='<%# Container.DataItem %>' 
     OnCheckedChanged="RoleCheckBox_CheckChanged" />

最後一項工作是完成 RoleCheckBox_CheckChanged 事件處理常式。 我們需要從參考引發事件的 CheckBox 控制項開始,因為此 CheckBox 實例會告知我們透過其 TextChecked 屬性檢查或取消核取的角色。 使用這項資訊以及所選使用者的 UserName,我們會透過 Roles 類別的 AddUserToRoleRemoveUserFromRole 方法,從角色新增或移除使用者。

protected void RoleCheckBox_CheckChanged(object sender, EventArgs e) 
{ 
     // Reference the CheckBox that raised this event 
     CheckBox RoleCheckBox = sender as CheckBox; 

     // Get the currently selected user and role 
     string selectedUserName = UserList.SelectedValue; 

     string roleName = RoleCheckBox.Text; 

     // Determine if we need to add or remove the user from this role 
     if (RoleCheckBox.Checked) 
     { 
          // Add the user to the role 
          Roles.AddUserToRole(selectedUserName, roleName); 
          // Display a status message 
          ActionStatus.Text = string.Format("User {0} was added to role {1}.", selectedUserName, roleName); 
     } 
     else 
     { 
          // Remove the user from the role 
          Roles.RemoveUserFromRole(selectedUserName, roleName); 
          // Display a status message 
          ActionStatus.Text = string.Format("User {0} was removed from role {1}.", selectedUserName, roleName); 

     } 
}

上述程式碼一開始會以程式設計方式參考引發事件的 CheckBox,此事件可透過 sender 輸入參數取得。 如果核取 CheckBox,則會將選取的使用者新增至指定的角色,否則會從角色中移除。 不論是哪一種情況,卷 ActionStatus 標會顯示一則訊息,摘要顯示剛執行的動作。

請花點時間透過瀏覽器測試此頁面。 選取使用者 Tito,然後將 Tito 新增至系統管理員和監督員角色。

Tito 已新增至系統管理員和監督員角色

圖 3:Tito 已新增至系統管理員和監督員角色, (按一下即可檢視大小完整的映射)

接下來,從下拉式清單中選取 [使用者暴力密碼]。 回傳會透過 CheckRolesForSelectedUser 更新重複項的 CheckBox。 由於 Bruce 尚未屬於任何角色,因此不會核取這兩個核取方塊。 接下來,將 Bruce 新增至監督員角色。

暴力密碼已新增至監督員角色

圖 4:已將暴力密碼新增至監督員角色 (按一下以檢視大小完整的影像)

若要進一步驗證 方法的功能 CheckRolesForSelectedUser ,請選取 Tito 或 Bruce 以外的使用者。 請注意核取方塊如何自動取消核取,表示它們不屬於任何角色。 返回 Tito。 應該同時核取 [系統管理員] 和 [監督員] 核取方塊。

步驟 2:建置「依角色」使用者介面

此時,我們已完成「依使用者」介面,並準備好開始處理「依角色」介面。 [依角色] 介面會提示使用者從下拉式清單中選取角色,然後在 GridView 中顯示屬於該角色的使用者集。

將另一個 DropDownList 控制項新增至 UsersAndRoles.aspx 頁面。 將此名稱放在 Repeater 控制項下方,將它命名為 RoleList ,並將其屬性設定 AutoPostBack 為 True。 在該底下,新增 GridView 並將它命名為 RolesUserList 。 此 GridView 會列出屬於所選角色的使用者。 將 GridView 的 AutoGenerateColumns 屬性設定為 False、將 TemplateField 新增至方格的 Columns 集合,並將其屬性設定 HeaderText 為 「Users」。 定義 TemplateField, ItemTemplate 讓它在名為 UserNameLabel 的 Label 屬性中 Text 顯示資料系結運算式 Container.DataItem 的值。

新增和設定 GridView 之後,您的「依角色」介面宣告式標記看起來應該類似下列:

<h3>Manage Users By Role</h3> 
<p> 
     <b>Select a Role:</b> 

     <asp:DropDownList ID="RoleList" runat="server" AutoPostBack="true"></asp:DropDownList> 
</p> 
<p>      <asp:GridView ID="RolesUserList" runat="server" AutoGenerateColumns="false" 

          EmptyDataText="No users belong to this role."> 
          <Columns> 
               <asp:TemplateField HeaderText="Users"> 
                    <ItemTemplate> 
                         <asp:Label runat="server" id="UserNameLabel" 
                              Text='<%# Container.DataItem %>'></asp:Label> 

                    </ItemTemplate> 
               </asp:TemplateField> 
          </Columns> 
     </asp:GridView> </p>

我們需要以系統中的角色集填入 RoleList DropDownList。 若要完成這項作業,請更新 BindRolesToList 方法,以便將 方法傳 Roles.GetAllRoles 回的字串陣列系結至 RolesList DropDownList (,以及 UsersRoleList Repeater) 。

private void BindRolesToList() 
{ 
     // Get all of the roles 

     string[] roles = Roles.GetAllRoles(); 
     UsersRoleList.DataSource = roles; 
     UsersRoleList.DataBind(); 

     RoleList.DataSource = roles; 
     RoleList.DataBind(); 
}

方法中的 BindRolesToList 最後兩行已新增,可將角色集系結至 RoleList DropDownList 控制項。 圖 5 顯示透過瀏覽器檢視的最終結果 – 填入系統角色的下拉式清單。

角色會顯示在 RoleList DropDownList 中

圖 5:角色會顯示在 RoleList DropDownList (按一下以檢視大小完整的影像)

顯示屬於所選角色的使用者

第一次載入頁面,或從 RoleList DropDownList 選取新角色時,我們需要在 GridView 中顯示屬於該角色的使用者清單。 使用下列程式碼建立名為 DisplayUsersBelongingToRole 的方法:

private void DisplayUsersBelongingToRole() 
{ 
     // Get the selected role 
     string selectedRoleName = RoleList.SelectedValue; 

     // Get the list of usernames that belong to the role 
     string[] usersBelongingToRole = Roles.GetUsersInRole(selectedRoleName); 

     // Bind the list of users to the GridView 
     RolesUserList.DataSource = usersBelongingToRole; 
     RolesUserList.DataBind(); 
}

這個方法從 DropDownList 取得選取的角色 RoleList 開始。 然後,Roles.GetUsersInRole(roleName)它會使用 方法來擷取屬於該角色之使用者的 UserNames 字串陣列。 此陣列接著會系結至 RolesUserList GridView。

在兩種情況下必須呼叫這個方法:頁面最初載入時,以及 DropDownList 中 RoleList 選取的角色變更時。 因此,更新 Page_Load 事件處理常式,以便在 呼叫 CheckRolesForSelectedUser 之後叫用這個方法。 接下來,建立 事件的 SelectedIndexChanged 事件處理常式 RoleList ,並從該處呼叫這個方法。

protected void Page_Load(object sender, EventArgs e) 
{ 
     if (!Page.IsPostBack) 
     { 
          // Bind the users and roles 
          BindUsersToUserList(); 
          BindRolesToList(); 

          // Check the selected user's roles 
          CheckRolesForSelectedUser(); 

          // Display those users belonging to the currently selected role 
          DisplayUsersBelongingToRole(); 
     } 
} 

... 

protected void RoleList_SelectedIndexChanged(object sender, EventArgs e) 
{ 
     DisplayUsersBelongingToRole(); 
}

有了此程式碼, RolesUserList GridView 應該會顯示屬於所選角色的使用者。 如圖 6 所示,監督員角色包含兩個成員:Bruce 和 Tito。

GridView 會列出屬於所選角色的使用者

圖 6:GridView 會列出屬於選取角色的使用者, (按一下即可檢視大小完整的映射)

從選取的角色移除使用者

讓我們增強 RolesUserList GridView,使其包含 [移除] 按鈕的資料行。 按一下特定使用者的 [移除] 按鈕將會從該角色中移除。

首先,將 [刪除] 按鈕欄位新增至 GridView。 讓此欄位顯示為最左邊的欄位,並將其屬性從 「Delete」 變更 DeleteText (預設) 為 「Remove」。

顯示如何在 [欄位] 視窗中新增 [移除] 按鈕的螢幕擷取畫面。

圖 7:將 [移除] 按鈕新增至 GridView (按一下即可檢視大小完整的影像)

按一下 [移除] 按鈕時,會進行回傳,並引發 GridView 的事件 RowDeleting 。 我們需要為此事件建立事件處理常式,並撰寫程式碼,以從選取的角色中移除使用者。 建立事件處理常式,然後新增下列程式碼:

protected void RolesUserList_RowDeleting(object sender, GridViewDeleteEventArgs e) 
{ 
     // Get the selected role 
     string selectedRoleName = RoleList.SelectedValue; 

     // Reference the UserNameLabel 
     Label UserNameLabel = RolesUserList.Rows[e.RowIndex].FindControl("UserNameLabel") as Label; 

     // Remove the user from the role 
     Roles.RemoveUserFromRole(UserNameLabel.Text, selectedRoleName); 

     // Refresh the GridView 
     DisplayUsersBelongingToRole(); 

     // Display a status message 
     ActionStatus.Text = string.Format("User {0} was removed from role {1}.", UserNameLabel.Text, selectedRoleName); 
}

程式碼會從判斷選取的角色名稱開始。 然後,它會以程式設計方式參考 UserNameLabel 按一下 [移除] 按鈕的資料列控制項,以判斷要移除之使用者的 UserName。 然後,使用者會透過 呼叫 Roles.RemoveUserFromRole 方法,從角色中移除。 RolesUserList然後會重新整理 GridView,並透過 ActionStatus 標籤控制項顯示訊息。

注意

從角色中移除使用者之前,[移除] 按鈕不需要使用者進行任何類型的確認。 我邀請您新增一些層級的使用者確認。 確認動作的最簡單方式之一是透過用戶端確認對話方塊。 如需這項技術的詳細資訊,請參閱 刪除時新增Client-Side確認

圖 8 顯示使用者 Tito 從監督員群組移除之後的頁面。

Alas,Tito 不再是主管

圖 8:Alas,Tito 不再是主管 (按一下即可檢視大小完整的影像)

將新使用者新增至選取的角色

除了從選取的角色移除使用者之外,此頁面的訪客也應該能夠將使用者新增至選取的角色。 將使用者新增至所選角色的最佳介面取決於您預期的使用者帳戶數目。 如果您的網站只包含數十個使用者帳戶或更少帳戶,您可以在這裡使用 DropDownList。 如果可能有數千個使用者帳戶,您會想要包含允許使用者流覽帳戶的使用者介面、搜尋特定帳戶,或以其他方式篩選使用者帳戶。

針對此頁面,讓我們使用非常簡單的介面,不論系統中的使用者帳戶數目為何。 也就是說,我們將使用 TextBox,提示訪客輸入想要新增至所選角色的使用者名稱。 如果沒有該名稱的使用者存在,或使用者已經是角色的成員,我們會在 [標籤] 中 ActionStatus 顯示訊息。 但是,如果使用者存在且不是角色的成員,我們會將它們新增至角色並重新整理方格。

在 GridView 下方新增 TextBox 和 Button。 將 TextBox ID 設定為 UserNameToAddToRole ,並將 Button 的 IDText 屬性分別設定為 AddUserToRoleButton 和 [將使用者新增至角色]。

<p> 
     <b>UserName:</b> 
     <asp:TextBox ID="UserNameToAddToRole" runat="server"></asp:TextBox> 
     <br /> 
     <asp:Button ID="AddUserToRoleButton" runat="server" Text="Add User to Role" /> 

</p>

接下來,建立 Click 的事件處理常式, AddUserToRoleButton 並新增下列程式碼:

protected void AddUserToRoleButton_Click(object sender, EventArgs e) 
{ 
     // Get the selected role and username 

     string selectedRoleName = RoleList.SelectedValue; 
     string userNameToAddToRole = UserNameToAddToRole.Text; 

     // Make sure that a value was entered 
     if (userNameToAddToRole.Trim().Length == 0) 
     { 
          ActionStatus.Text = "You must enter a username in the textbox."; 
          return; 
     } 

     // Make sure that the user exists in the system 
     MembershipUser userInfo = Membership.GetUser(userNameToAddToRole); 
     if (userInfo == null) 
     { 
          ActionStatus.Text = string.Format("The user {0} does not exist in the system.", userNameToAddToRole); 

          return; 
     } 

     // Make sure that the user doesn't already belong to this role 
     if (Roles.IsUserInRole(userNameToAddToRole, selectedRoleName)) 
     { 
          ActionStatus.Text = string.Format("User {0} already is a member of role {1}.", userNameToAddToRole, selectedRoleName); 
          return; 
     } 

     // If we reach here, we need to add the user to the role 
     Roles.AddUserToRole(userNameToAddToRole, selectedRoleName); 

     // Clear out the TextBox 
     UserNameToAddToRole.Text = string.Empty; 

     // Refresh the GridView 
     DisplayUsersBelongingToRole(); 

     // Display a status message 

     ActionStatus.Text = string.Format("User {0} was added to role {1}.", userNameToAddToRole, selectedRoleName); }

事件處理常式中的 Click 大部分程式碼會執行各種驗證檢查。 它可確保訪客在 TextBox 中 UserNameToAddToRole 提供使用者名稱、使用者存在於系統中,而且他們尚未屬於選取的角色。 如果上述任一檢查失敗,則會在 中 ActionStatus 顯示適當的訊息,並結束事件處理常式。 如果所有檢查都通過,則會透過 Roles.AddUserToRole 方法將使用者新增至角色。 接著,會清除 TextBox 的 Text 屬性、重新整理 GridView,而 ActionStatus Label 會顯示一則訊息,指出指定的使用者已成功新增至選取的角色。

注意

為了確保指定的使用者尚未屬於選取的角色,我們使用Roles.IsUserInRole(userName, roleName) 方法,這個方法會傳回 Boolean 值,指出userName是否為roleName的成員。 當我們查看角色型授權時, 我們將在下一個教學課程中再次使用此方法。

透過瀏覽器流覽頁面,然後從 RoleList DropDownList 選取監督員角色。 嘗試輸入不正確使用者名稱 – 您應該會看到一則訊息,說明使用者不存在於系統中。

您無法將不存在的使用者新增至角色

圖 9:您無法將不存在的使用者新增至角色, (按一下即可檢視完整大小的影像)

現在請嘗試新增有效的使用者。 繼續並將 Tito 重新新增至監督員角色。

Tito 再次成為監督員!

圖 10:Tito 再次成為監督員! (按一下即可檢視完整大小的影像)

步驟 3:交叉更新「依使用者」和「依角色」介面

此頁面 UsersAndRoles.aspx 提供兩個不同的介面來管理使用者和角色。 目前,這兩個介面彼此獨立運作,因此在一個介面中所做的變更可能不會立即反映在另一個介面中。 例如,假設頁面的訪客會從 RoleList DropDownList 中選取監督員角色,其中會列出 Bruce 和 Tito 作為其成員。 接下來,訪客會從 UserList DropDownList 中選取 Tito,這會檢查重複程式中的 UsersRoleList [系統管理員] 和 [監督員] 核取方塊。 如果訪客接著從 Repeater 取消核取監督員角色,Tito 就會從監督員角色中移除,但這項修改不會反映在「依角色」介面中。 GridView 仍會將 Tito 顯示為監督員角色的成員。

若要修正此問題,我們需要在重複程式核取或取消核 UsersRoleList 取角色時,重新整理 GridView。 同樣地,每當使用者從「依角色」介面移除或新增至角色時,我們需要重新整理 Repeater。

呼叫 方法會重新 CheckRolesForSelectedUser 整理「依使用者」介面中的 Repeater。 您可以在 GridView 的 RowDeleting 事件處理常式和 AddUserToRoleButton Button 的 Click 事件處理常式中 RolesUserList 修改 「by role」 介面。 因此,我們需要從每個方法呼叫 CheckRolesForSelectedUser 方法。

protected void RolesUserList_RowDeleting(object sender, GridViewDeleteEventArgs e) 
{ 
     ... Code removed for brevity ... 

     // Refresh the "by user" interface 
     CheckRolesForSelectedUser(); 
} 

protected void AddUserToRoleButton_Click(object sender, EventArgs e) 
{ 
     ... Code removed for brevity ... 


     // Refresh the "by user" interface 
     CheckRolesForSelectedUser(); 
}

同樣地,呼叫 方法會重新 DisplayUsersBelongingToRole 整理 「by role」 介面中的 GridView,並透過 RoleCheckBox_CheckChanged 事件處理常式修改 「by user」 介面。 因此,我們需要從這個事件處理常式呼叫 DisplayUsersBelongingToRole 方法。

protected void RoleCheckBox_CheckChanged(object sender, EventArgs e) 
{ 
     ... Code removed for brevity... 

     // Refresh the "by role" interface 
     DisplayUsersBelongingToRole(); 
}

隨著這些次要程式碼變更,「依使用者」和「依角色」介面現在已正確交叉更新。 若要確認這一點,請流覽瀏覽器的頁面,然後分別從 UserList 和 DropDownLists 選取 [Tito] 和 RoleList [監督員]。 請注意,當您從 「依使用者」介面的 Repeater 取消核取 Tito 的監督員角色時,Tito 會自動從 「依角色」介面的 GridView 中移除。 從 [依角色] 介面將 Tito 新增回監督員角色,會自動重新檢查 [依使用者] 介面中的 [監督員] 核取方塊。

步驟 4:自訂 CreateUserWizard 以包含「指定角色」步驟

在建立使用者帳戶教學 課程中,我們已瞭解如何使用 CreateUserWizard Web 控制項來提供建立新使用者帳戶的介面。 CreateUserWizard 控制項可以使用下列兩種方式之一:

  • 作為一種方法,訪客在網站上建立自己的使用者帳戶,以及
  • 作為系統管理員建立新帳戶的方法

在第一個使用案例中,訪客會前往網站並填寫 CreateUserWizard,輸入其資訊以在網站上註冊。 第二個案例中,系統管理員會為另一個人建立新的帳戶。

當系統管理員為其他人建立帳戶時,允許系統管理員指定新使用者帳戶所屬的角色可能會很有説明。 在 儲存其他使用者資訊教學課程中,我們已瞭解如何藉由新增其他 WizardSteps 來自訂 CreateUserWizard。 讓我們看看如何將額外的步驟新增至 CreateUserWizard,以指定新使用者的角色。

CreateUserWizardWithRoles.aspx開啟頁面,然後新增名為 的 RegisterUserWithRoles CreateUserWizard 控制項。 將控制項的 ContinueDestinationPageUrl 屬性設定為 「~/Default.aspx」。 因為這裡的概念是系統管理員會使用此 CreateUserWizard 控制項來建立新的使用者帳戶,請將控制項的 LoginCreatedUser 屬性設定為 False。 這個 LoginCreatedUser 屬性會指定訪客是否自動以剛建立的使用者身分登入,而且預設為 True。 我們會將它設定為 False,因為當系統管理員建立新帳戶時,我們想要讓他以自己身分登入。

接下來,選取 [新增/移除 WizardSteps ...]從 CreateUserWizard 的智慧標籤選項,並將新的 WizardStep 設定為 IDSpecifyRolesStep 。 移動 , SpecifyRolesStep WizardStep 使其出現在「註冊新帳戶」步驟之後,但在「完成」步驟之前。 將 WizardStepTitle 屬性設定為 「Specify Roles」,將其 屬性設定為 Step ,並將其 StepTypeAllowReturn 屬性設定為 False。

此螢幕擷取畫面顯示 [精靈步驟集合編輯器] 視窗中選取的 [指定角色] 屬性。

圖 11:將 [指定角色 WizardStep ] 新增至 CreateUserWizard (按一下即可檢視大小完整的映射)

在此變更之後,CreateUserWizard 的宣告式標記看起來應該如下所示:

<asp:CreateUserWizard ID="RegisterUserWithRoles" runat="server" 
     ContinueDestinationPageUrl="~/Default.aspx" LoginCreatedUser="False"> 

     <WizardSteps> 
          <asp:CreateUserWizardStep ID="CreateUserWizardStep1" runat="server"> 
          </asp:CreateUserWizardStep> 
          <asp:WizardStep ID="SpecifyRolesStep" runat="server" StepType="Step" 

               Title="Specify Roles" AllowReturn="False"> 
          </asp:WizardStep> 
          <asp:CompleteWizardStep ID="CompleteWizardStep1" runat="server"> 
          </asp:CompleteWizardStep> 
     </WizardSteps> 

</asp:CreateUserWizard>

在 [指定角色] 中 WizardStep ,新增名為 的 RoleList CheckBoxList。 此 CheckBoxList 會列出可用的角色,讓流覽頁面的人員檢查新建立使用者所屬的角色。

我們留下兩個程式碼撰寫工作:首先,我們必須在 CheckBoxList 中填 RoleList 入系統中的角色;其次,當使用者從 [指定角色] 步驟移至 [完成] 步驟時,必須將建立的使用者新增至選取的角色。 我們可以完成事件處理常式中的第一項 Page_Load 工作。 下列程式碼會以程式設計方式參考 RoleList 第一次造訪頁面的 CheckBox,並將系統中的角色系結至該頁面。

protected void Page_Load(object sender, EventArgs e) 
{ 
     if (!Page.IsPostBack) 
     { 
          // Reference the SpecifyRolesStep WizardStep 
          WizardStep SpecifyRolesStep = RegisterUserWithRoles.FindControl("SpecifyRolesStep") as WizardStep; 

          // Reference the RoleList CheckBoxList 
          CheckBoxList RoleList = SpecifyRolesStep.FindControl("RoleList") as CheckBoxList; 

          // Bind the set of roles to RoleList 
          RoleList.DataSource = Roles.GetAllRoles(); 
          RoleList.DataBind(); 
     } 
}

上述程式碼看起來應該很熟悉。 在 儲存其他使用者資訊教學課程中,我們使用兩 FindControl 個 語句從自訂 WizardStep 內參考 Web 控制項。 並將角色系結至 CheckBoxList 的程式碼取自本教學課程稍早的 。

為了執行第二個程式設計工作,我們需要知道「指定角色」步驟何時完成。 回想一下,CreateUserWizard 有事件 ActiveStepChanged ,每次訪客從一個步驟巡覽到另一個步驟時都會引發。 在這裡,我們可以判斷使用者是否已達到「完成」步驟;如果是,我們需要將使用者新增至選取的角色。

建立 事件的事件處理常式 ActiveStepChanged ,並新增下列程式碼:

protected void RegisterUserWithRoles_ActiveStepChanged(object sender, EventArgs e) 
{ 
     // Have we JUST reached the Complete step? 
     if (RegisterUserWithRoles.ActiveStep.Title == "Complete") 
     { 
          // Reference the SpecifyRolesStep WizardStep 
          WizardStep SpecifyRolesStep = RegisterUserWithRoles.FindControl("SpecifyRolesStep") as WizardStep; 

          // Reference the RoleList CheckBoxList 
          CheckBoxList RoleList = SpecifyRolesStep.FindControl("RoleList") as CheckBoxList; 

          // Add the checked roles to the just-added user 
          foreach (ListItem li in RoleList.Items) 

          { 
               if (li.Selected) 
                    Roles.AddUserToRole(RegisterUserWithRoles.UserName, li.Text); 
          } 
     } 
}

如果使用者剛到達 「已完成」步驟,事件處理常式會列舉 CheckBoxList 的專案 RoleList ,並將剛建立的使用者指派給選取的角色。

透過瀏覽器流覽此頁面。 CreateUserWizard 中的第一個步驟是標準「註冊新帳戶」步驟,它會提示新使用者的使用者名稱、密碼、電子郵件和其他金鑰資訊。 輸入資訊以建立名為 Wanda 的新使用者。

建立名為 Wanda 的新使用者

圖 12:建立名為 Wanda 的新使用者 (按一下即可檢視完整大小的映射)

按一下 [建立使用者] 按鈕。 CreateUserWizard 會在內部呼叫 Membership.CreateUser 方法、建立新的使用者帳戶,然後繼續進行下一個步驟「指定角色」。此處列出系統角色。 核取 [監督員] 核取方塊,然後按 [下一步]。

讓 Wanda 成為主管角色的成員

圖 13:將 Wanda 設為監督員角色的成員 (按一下即可檢視全大小影像)

按 [下一步] 會導致回傳,並將 更新 ActiveStep 為 「完成」步驟。 在 ActiveStepChanged 事件處理常式中,最近建立的使用者帳戶會指派給監督員角色。 若要確認這一點,請返回 UsersAndRoles.aspx 頁面,然後從 RoleList DropDownList 選取 [監督員]。 如圖 14 所示,監督員現在由三個使用者組成:Bruce、Tito 和 Wanda。

Bruce、Tito 和 Wanda 都是所有主管

圖 14:Bruce、Tito 和 Wanda 是 [所有監督員] (按一下即可檢視完整大小的影像)

摘要

角色架構提供方法來擷取特定使用者角色的相關資訊,以及判斷使用者屬於指定角色的方法。 此外,還有一些方法可將一或多個使用者新增和移除至一或多個角色。 在本教學課程中,我們只著重于下列兩種方法: AddUserToRoleRemoveUserFromRole 。 另外還有一些變體,其設計目的是要將多個使用者新增至單一角色,以及將多個角色指派給單一使用者。

本教學課程也包含擴充 CreateUserWizard 控制項,以包含 WizardStep 以指定新建立使用者的角色。 這類步驟可協助系統管理員簡化為新使用者建立使用者帳戶的程式。

此時,我們已瞭解如何建立和刪除角色,以及如何新增和移除角色中的使用者。 但我們尚未探討如何套用以角色為基礎的授權。 在下列教學 課程中,我們將探討以角色為基礎定義 URL 授權規則,以及如何根據目前登入的使用者角色來限制頁面層級功能。

快樂的程式設計!

深入閱讀

如需本教學課程中所討論之主題的詳細資訊,請參閱下列資源:

關於作者

Scott Mitchell 是多個 ASP/ASP.NET 書籍的作者,以及 4GuysFromRolla.com 的建立者,自 1998 年起就與 Microsoft Web 技術合作。 Scott 是獨立的顧問、訓練者和作者。 他的最新書籍是 Sams 在 24 小時內自行 ASP.NET 2.0。 Scott 可以透過 mitchell@4guysfromrolla.com 在 上的部落格或透過 http://ScottOnWriting.NET 其部落格來連線。

特別感謝...

本教學課程系列是由許多實用的檢閱者所檢閱。 本教學課程的首席檢閱者是 Teresa Murphy。 想要檢閱即將推出的 MSDN 文章嗎? 如果是,請將一行放在 mitchell@4GuysFromRolla.com