將角色指派給使用者 (VB)
注意
自本文撰寫以來,ASP.NET 成員資格提供者已被 ASP.NET 身分識別取代。 強烈建議您更新應用程式以使用 ASP.NET 身分識別 平臺,而不是本文撰寫時精選的成員資格提供者。 ASP.NET 身分識別對於 ASP.NET 成員資格系統有一些優點,包括 :
- 更好的效能
- 改善擴充性和可測試性
- 支援 OAuth、OpenID Connect 和雙因素驗證
- 宣告型身分識別支援
- 與 ASP.Net Core 更好的互通性
在本教學課程中,我們將建置兩個 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顯示此效果。
圖 1:標籤 CssClass
的屬性會產生大型、紅色字型 (按一下即可檢視完整大小的影像)
接下來,將 DropDownList 新增至頁面、將其 ID
屬性設定為 UserList
,並將其屬性設定 AutoPostBack
為 True。 我們將使用此 DropDownList 列出系統中的所有使用者。 這個 DropDownList 將會系結至 MembershipUser 物件的集合。 由於我們想要 DropDownList 顯示 MembershipUser 物件的 UserName 屬性 (,並將其作為清單專案的值) ,請將 DropDownList 的 DataTextField
和 DataValueField
屬性設定為 「UserName」。
在 DropDownList 底下,新增名為 UsersRoleList
的重複項。 此重複程式會將系統中的所有角色列為一系列核取方塊。 使用下列宣告式標記定義 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 Sub BindUsersToUserList()
' Get all of the user accounts
Dim users As MembershipUserCollection = Membership.GetAllUsers()
UserList.DataSource = users
UserList.DataBind()
End Sub
Private Sub BindRolesToList()
' Get all of the roles
Dim roleNames() As String = Roles.GetAllRoles()
UsersRoleList.DataSource = roleNames
UsersRoleList.DataBind()
End Sub
方法 BindUsersToUserList
會透過Membership.GetAllUsers
方法擷取系統中的所有使用者帳戶。 這會傳MembershipUserCollection
回 物件,這是 實例的MembershipUser
集合。 此集合接著會系結至 UserList
DropDownList。 MembershipUser
集合中的實例包含各種屬性,例如 UserName
、 Email
、 CreationDate
和 IsOnline
。 若要指示 DropDownList 顯示內容的值 UserName
,請確定 UserList
DropDownList 的 DataTextField
和 DataValueField
屬性已設定為 「UserName」。
注意
方法 Membership.GetAllUsers
有兩個多載:一個不接受任何輸入參數並傳回所有使用者,另一個接受頁面索引和頁面大小的整數值,並只傳回指定的使用者子集。 當可分頁的使用者介面元素中顯示大量的使用者帳戶時,第二個多載可用來更有效率地逐頁流覽使用者,因為它只會傳回使用者帳戶的精確子集,而不是全部的使用者帳戶。
方法 BindRolesToList
會從呼叫 Roles
類別的GetAllRoles
方法開始,這個方法會傳回包含系統中角色的字串陣列。 此字串陣列接著會系結至 Repeater。
最後,第一次載入頁面時,我們需要呼叫這兩種方法。 將下列程式碼加入至 Page_Load
事件處理常式:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not Page.IsPostBack Then
' Bind the users and roles
BindUsersToUserList()
BindRolesToList()
End If
End Sub
完成此程式碼之後,請花點時間流覽頁面,流覽瀏覽器;您的畫面看起來應該類似圖 2。 所有使用者帳戶都會填入下拉式清單中,在該清單中,每個角色都會顯示為核取方塊。 因為我們將 AutoPostBack
DropDownList 和 CheckBoxes 的屬性設定為 True,所以變更選取的使用者或檢查或取消核取角色會導致回傳。 不過,沒有執行任何動作,因為我們尚未撰寫程式碼來處理這些動作。 我們將在後續兩節中處理這些工作。
圖 2:頁面會顯示 [使用者和角色] (按一下即可檢視大小完整的影像)
檢查所選使用者所屬的角色
第一次載入頁面時,或每當訪客從下拉式清單中選取新的使用者時,我們需要更新 UsersRoleList
的核取方塊,以便只有在選取的使用者屬於該角色時,才會核取指定的角色核取方塊。 若要達成此目的,請使用下列程式碼建立名為 CheckRolesForSelectedUser
的方法:
Private Sub CheckRolesForSelectedUser()
' Determine what roles the selected user belongs to
Dim selectedUserName As String = UserList.SelectedValue
Dim selectedUsersRoles() As String = Roles.GetRolesForUser(selectedUserName)
' Loop through the Repeater's Items and check or uncheck the checkbox as needed
For Each ri As RepeaterItem In UsersRoleList.Items
' Programmatically reference the CheckBox
Dim RoleCheckBox As CheckBox = CType(ri.FindControl("RoleCheckBox"), CheckBox)
' See if RoleCheckBox.Text is in selectedUsersRoles
If Linq.Enumerable.Contains(Of String)(selectedUsersRoles, RoleCheckBox.Text) Then
RoleCheckBox.Checked = True
Else
RoleCheckBox.Checked = False
End If
Next
End Sub
上述程式碼會從判斷所選使用者是誰開始。 然後,它會使用 Roles 類別的 GetRolesForUser(userName)
方法,將指定的使用者角色集當做字串陣列傳回。 接下來,會列舉重複項的專案,並且會以程式設計方式參考每個專案的 RoleCheckBox
CheckBox。 只有在它對應的角色包含在字串陣列中 selectedUsersRoles
時,才會檢查 CheckBox。
注意
Linq.Enumerable.Contains(Of String)(...)
如果您使用 ASP.NET 2.0 版,語法將不會編譯。 方法是 Contains(Of String)
LINQ 程式庫的一部分,這是 ASP.NET 3.5 的新功能。 如果您仍在使用 ASP.NET 2.0 版,請改用Array.IndexOf(Of String)
方法。
CheckRolesForSelectedUser
必須在兩種情況下呼叫 方法:第一次載入頁面時,以及每當 UserList
DropDownList 選取的索引變更時。 因此,從 Page_Load
事件處理常式呼叫 和 BindRolesToList
) 之後 (呼叫 BindUsersToUserList
這個方法。 此外,請為 DropDownList 的事件 SelectedIndexChanged
建立事件處理常式,並從該處呼叫此方法。
Protected Sub Page_Load(ByVal sender As Object,ByVal e As System.EventArgs) Handles Me.Load
If Not Page.IsPostBack Then
' Bind the users and roles
BindUsersToUserList()
BindRolesToList()
' Check the selected user's roles
CheckRolesForSelectedUser()
End If
End Sub
...
Protected Sub UserList_SelectedIndexChanged(ByVal sender As Object,ByVal e As System.EventArgs) Handles UserList.SelectedIndexChanged
CheckRolesForSelectedUser()
End Sub
有了此程式碼,您可以透過瀏覽器測試頁面。 不過,由於 UsersAndRoles.aspx
頁面目前缺乏將使用者指派給角色的能力,因此沒有任何使用者具有角色。 我們會在一段時間建立將使用者指派給角色的介面,讓您可以接受此程式碼運作的字組,並在稍後驗證它是否正常運作,或者您可以將記錄插入資料表,以手動將使用者新增至 aspnet_UsersInRoles
角色,以便立即測試這項功能。
從角色指派和移除使用者
當訪客在重複程式中檢查或取消核取 CheckBox UsersRoleList
時,我們需要從對應的角色新增或移除選取的使用者。 CheckBox 的 AutoPostBack
屬性目前設定為 True,每當檢查或取消核取重複程式中的 CheckBox 時,就會產生回傳。 簡單地說,我們需要建立 CheckBox CheckChanged
事件的事件處理常式。 由於 CheckBox 位於 Repeater 控制項中,因此我們需要手動新增事件處理常式管線。 首先,將事件處理常式新增至程式碼後置類別作為 Protected
方法,如下所示:
Protected Sub RoleCheckBox_CheckChanged(ByVal sender As Object, ByVal e As EventArgs)
End Sub
我們會在一段時間傳回撰寫此事件處理常式的程式碼。 但首先,讓我們完成事件處理管線。 從 Repeater 的 ItemTemplate
中的 CheckBox,新增 OnCheckedChanged="RoleCheckBox_CheckChanged"
。 此語法會將 RoleCheckBox_CheckChanged
事件處理常式連線至 RoleCheckBox
的 CheckedChanged
事件。
<asp:CheckBox runat="server" ID="RoleCheckBox"
AutoPostBack="true"
Text='<%# Container.DataItem %>'
OnCheckedChanged="RoleCheckBox_CheckChanged" />
最後一項工作是完成 RoleCheckBox_CheckChanged
事件處理常式。 我們需要從參考引發事件的 CheckBox 控制項開始,因為此 CheckBox 實例會告知我們透過其 Text
和 Checked
屬性檢查或取消核取的角色。 使用這項資訊以及所選使用者的 UserName,我們會透過 Roles
類別的 AddUserToRole
或RemoveUserFromRole
方法,從角色新增或移除使用者。
Protected Sub RoleCheckBox_CheckChanged(ByVal sender As Object, ByVal e As EventArgs)
'Reference the CheckBox that raised this event
Dim RoleCheckBox As CheckBox = CType(sender, CheckBox)
' Get the currently selected user and role
Dim selectedUserName As String = UserList.SelectedValue
Dim roleName As String = RoleCheckBox.Text
' Determine if we need to add or remove the user from this role
If RoleCheckBox.Checked Then
' 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)
End If
End Sub
上述程式碼一開始會以程式設計方式參考引發事件的 CheckBox,該事件可透過 sender
輸入參數取得。 如果核取 CheckBox,則選取的使用者會新增至指定的角色,否則會從角色中移除它們。 不論是哪一種情況, ActionStatus
標籤都顯示一則訊息,摘要顯示剛執行的動作。
請花點時間透過瀏覽器測試此頁面。 選取使用者 Tito,然後將 Tito 新增至系統管理員和監督員角色。
圖 3:Tito 已新增至系統管理員和監督員角色, (按一下即可檢視完整大小的映射)
接下來,從下拉式清單中選取 [使用者暴力密碼]。 有回傳,而 Repeater 的 CheckBox 會透過 CheckRolesForSelectedUser
更新。 由於 Bruce 尚未屬於任何角色,因此不會核取這兩個核取方塊。 接下來,將 Bruce 新增至監督員角色。
圖 4:已將暴力密碼新增至監督員角色 (按一下即可檢視完整大小的影像)
若要進一步確認 方法的功能 CheckRolesForSelectedUser
,請選取 Tito 或 Bruce 以外的使用者。 請注意核取方塊如何自動取消核取,表示它們不屬於任何角色。 返回 Tito。 應該同時核取 [系統管理員] 和 [監督員] 核取方塊。
步驟 2:建置「依角色」使用者介面
此時,我們已完成「依使用者」介面,並準備好開始處理「依角色」介面。 [依角色] 介面會提示使用者從下拉式清單中選取角色,然後在 GridView 中顯示屬於該角色的使用者集。
將另一個 DropDownList 控制項新增至 UsersAndRoles.aspx page
。 將這一個放在 Repeater 控制項底下,將它 AutoPostBack
命名為 RoleList
,並將其屬性設定為 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 Sub BindRolesToList()
' Get all of the roles
Dim roleNames() As String = Roles.GetAllRoles()
UsersRoleList.DataSource = roleNames
UsersRoleList.DataBind()
RoleList.DataSource = roleNames
RoleList.DataBind()
End Sub
方法中的 BindRolesToList
最後兩行已新增,可將角色集系結至 RoleList
DropDownList 控制項。 圖 5 顯示透過瀏覽器檢視的最終結果 – 填入系統角色的下拉式清單。
圖 5:角色會顯示在 RoleList
DropDownList (按一下以檢視完整大小的影像)
顯示屬於所選角色的使用者
第一次載入頁面,或從 RoleList
DropDownList 選取新角色時,我們需要在 GridView 中顯示屬於該角色的使用者清單。 使用下列程式碼建立名為 DisplayUsersBelongingToRole
的方法:
Private Sub DisplayUsersBelongingToRole()
' Get the selected role
Dim selectedRoleName As String = RoleList.SelectedValue
' Get the list of usernames that belong to the role
Dim usersBelongingToRole() As String = Roles.GetUsersInRole(selectedRoleName)
' Bind the list of users to the GridView
RolesUserList.DataSource = usersBelongingToRole
RolesUserList.DataBind()
End Sub
這個方法首先會從 RoleList
DropDownList 取得選取的角色。 然後,Roles.GetUsersInRole(roleName)
它會使用 方法來擷取屬於該角色之使用者的 UserNames 字串陣列。 此陣列接著會系結至 RolesUserList
GridView。
這個方法必須在兩種情況下呼叫:頁面一開始載入時,以及 DropDownList 中 RoleList
選取的角色變更時。 因此,請更新 Page_Load
事件處理常式,以便在 呼叫 CheckRolesForSelectedUser
之後叫用這個方法。 接下來,建立 事件的 SelectedIndexChanged
事件處理常式 RoleList
,並從該處呼叫這個方法。
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not Page.IsPostBack Then
' Bind the users and roles
BindUsersToUserList()
BindRolesToList()
' Check the selected user's roles
CheckRolesForSelectedUser()
'Display those users belonging to the currently selected role
DisplayUsersBelongingToRole()
End If
End Sub
...
Protected Sub RoleList_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles RoleList.SelectedIndexChanged
DisplayUsersBelongingToRole()
End Sub
有了此程式碼, RolesUserList
GridView 應該會顯示屬於所選角色的使用者。 如圖 6 所示,監督員角色包含兩個成員:Bruce 和 Tito。
圖 6:GridView 會列出屬於所選角色的使用者, (按一下即可檢視全大小影像)
從選取的角色移除使用者
讓我們增強 RolesUserList
GridView,使其包含 「移除」按鈕的資料行。 按一下特定使用者的 [移除] 按鈕,將會從該角色中移除它們。
首先,將 [刪除] 按鈕欄位新增至 GridView。 將此欄位顯示為最左邊的欄位,並將其 DeleteText
屬性從 「Delete」 變更 (預設) 為 「Remove」。
圖 7:將 [移除] 按鈕新增至 GridView (按一下即可檢視全大小影像)
當按一下 [移除] 按鈕時,就會出現回傳,並引發 GridView 的事件 RowDeleting
。 我們需要為此事件建立事件處理常式,並撰寫程式碼,以從選取的角色中移除使用者。 建立事件處理常式,然後新增下列程式碼:
Protected Sub RolesUserList_RowDeleting(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewDeleteEventArgs) Handles RolesUserList.RowDeleting
' Get the selected role
Dim selectedRoleName As String = RoleList.SelectedValue
' Reference the UserNameLabel
Dim UserNameLabel As Label = CType(RolesUserList.Rows(e.RowIndex).FindControl("UserNameLabel"),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)
End Sub
程式碼會從判斷選取的角色名稱開始。 然後,它會以程式設計方式參考 UserNameLabel
按一下其 [移除] 按鈕之資料列中的控制項,以判斷要移除之使用者的 UserName。 然後,使用者會透過呼叫 Roles.RemoveUserFromRole
方法,從角色中移除。 RolesUserList
然後會重新整理 GridView,並透過 ActionStatus
Label 控制項顯示訊息。
注意
從角色中移除使用者之前,[移除] 按鈕不需要對使用者進行任何類型的確認。 我邀請您新增一些層級的使用者確認。 確認動作最簡單的方式之一是透過用戶端確認對話方塊。 如需這項技術的詳細資訊,請參閱 刪除時新增Client-Side確認。
圖 8 顯示使用者 Tito 從監督員群組中移除之後的頁面。
圖 8:Alas, Tito 不再是監督員 (按一下即可檢視完整大小的影像)
將新使用者新增至選取的角色
除了從選取的角色中移除使用者之外,此頁面的訪客也應該能夠將使用者新增至選取的角色。 將使用者新增至所選角色的最佳介面取決於您預期的使用者帳戶數目。 如果您的網站只存放數十個使用者帳戶或更少帳戶,您可以在這裡使用 DropDownList。 如果可能有數千個使用者帳戶,您會想要包含允許使用者流覽帳戶的使用者介面、搜尋特定帳戶,或以其他方式篩選使用者帳戶。
針對此頁面,讓我們使用非常簡單的介面,不論系統中的使用者帳戶數目為何。 也就是說,我們將使用 TextBox,提示訪客輸入想要新增至所選角色的使用者名稱。 如果沒有任何具有該名稱的使用者存在,或使用者已經是角色的成員,我們會在標籤中 ActionStatus
顯示訊息。 但如果使用者存在且不是角色的成員,我們會將它們新增至角色並重新整理方格。
在 GridView 下方新增 TextBox 和 Button。 將 TextBox 設定為 ID
UserNameToAddToRole
,並將 Button 的 ID
和 Text
屬性分別設定為 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 Sub AddUserToRoleButton_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles AddUserToRoleButton.Click
' Get the selected role and username
Dim selectedRoleName As String = RoleList.SelectedValue
Dim userToAddToRole As String = UserNameToAddToRole.Text
' Make sure that a value was entered
If userToAddToRole.Trim().Length = 0 Then
ActionStatus.Text = "You must enter a username in the textbox."
Exit Sub
End If
' Make sure that the user exists in the system
Dim userInfo As MembershipUser = Membership.GetUser(userToAddToRole)
If userInfo Is Nothing Then
ActionStatus.Text = String.Format("The user {0} does not exist in the system.",userNameToAddToRole)
Exit Sub
End If
' Make sure that the user doesn't already belong to this role
If Roles.IsUserInRole(userToAddToRole, selectedRoleName) Then
ActionStatus.Text = String.Format("User {0} already is a member of role {1}.", UserNameToAddToRole,selectedRoleName)
Exit Sub
End If
' If we reach here, we need to add the user to the role
Roles.AddUserToRole(userToAddToRole, 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)
End Sub
事件處理常式中的 Click
大部分程式碼會執行各種驗證檢查。 它可確保訪客在 TextBox 中 UserNameToAddToRole
提供使用者名稱、使用者存在於系統中,而且他們尚未屬於選取的角色。 如果上述任一檢查失敗,則會在 中 ActionStatus
顯示適當的訊息,並結束事件處理常式。 如果所有檢查都通過,則會透過 Roles.AddUserToRole
方法將使用者新增至角色。 接著,會清除 TextBox 的 Text
屬性、重新整理 GridView,而 ActionStatus
Label 會顯示一則訊息,指出指定的使用者已成功新增至選取的角色。
注意
為了確保指定的使用者尚未屬於選取的角色,我們使用Roles.IsUserInRole(userName, roleName)
方法,這個方法會傳回 Boolean 值,指出userName是否為roleName的成員。 當我們查看角色型授權時, 我們將在下一個教學課程中再次使用此方法。
透過瀏覽器流覽頁面,然後從 RoleList
DropDownList 選取監督員角色。 嘗試輸入不正確使用者名稱 – 您應該會看到一則訊息,說明使用者不存在於系統中。
圖 9:您無法將不存在的使用者新增至角色, (按一下即可檢視完整大小的影像)
現在請嘗試新增有效的使用者。 繼續並將 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 Sub RolesUserList_RowDeleting(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewDeleteEventArgs) Handles RolesUserList.RowDeleting
... Code removed for brevity ...
' Refresh the "by user" interface
CheckRolesForSelectedUser()
End Sub
Protected Sub AddUserToRoleButton_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles AddUserToRoleButton.Click
... Code removed for brevity ...
' Refresh the "by user" interface
CheckRolesForSelectedUser()
End Sub
同樣地,呼叫 方法會重新 DisplayUsersBelongingToRole
整理 「by role」 介面中的 GridView,並透過 RoleCheckBox_CheckChanged
事件處理常式修改 「by user」 介面。 因此,我們需要從這個事件處理常式呼叫 DisplayUsersBelongingToRole
方法。
Protected Sub RoleCheckBox_CheckChanged(ByVal sender As Object, ByVal e As EventArgs)
... Code removed for brevity ...
' Refresh the "by role" interface
DisplayUsersBelongingToRole()
End Sub
隨著這些次要程式碼變更,「依使用者」和「依角色」介面現在已正確交叉更新。 若要確認這一點,請流覽瀏覽器的頁面,然後分別從 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
設定為 ID
SpecifyRolesStep
。 移動 , SpecifyRolesStep WizardStep
使其出現在「註冊新帳戶」步驟之後,但在「完成」步驟之前。 將 WizardStep
的 Title
屬性設定為 「Specify Roles」,將其 屬性設定為 Step
,並將其 StepType
AllowReturn
屬性設定為 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.
This CheckBoxList 的 CheckBoxList 會列出可用的角色,讓流覽頁面的人員檢查新建立使用者所屬的角色。
我們留下兩個程式碼撰寫工作:首先,我們必須在 CheckBoxList 中填 RoleList
入系統中的角色;其次,當使用者從 [指定角色] 步驟移至 [完成] 步驟時,必須將建立的使用者新增至選取的角色。 我們可以完成事件處理常式中的第一項 Page_Load
工作。 下列程式碼會以程式設計方式參考 RoleList
第一次造訪頁面的 CheckBox,並將系統中的角色系結至該頁面。
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not Page.IsPostBack Then
' Reference the SpecifyRolesStep WizardStep
Dim SpecifyRolesStep As WizardStep = CType(RegisterUserWithRoles.FindControl("SpecifyRolesStep"),WizardStep)
' Reference the RoleList CheckBoxList
Dim RoleList As CheckBoxList = CType(SpecifyRolesStep.FindControl("RoleList"), CheckBoxList)
' Bind the set of roles to RoleList
RoleList.DataSource = Roles.GetAllRoles()
RoleList.DataBind()
End If
End Sub
上述程式碼看起來應該很熟悉。 在 儲存其他使用者資訊教學課程中,我們使用兩 FindControl
個 語句從自訂 WizardStep
內參考 Web 控制項。 並將角色系結至 CheckBoxList 的程式碼取自本教學課程稍早的 。
為了執行第二個程式設計工作,我們需要知道「指定角色」步驟何時完成。 回想一下,CreateUserWizard 有事件 ActiveStepChanged
,每次訪客從一個步驟巡覽到另一個步驟時都會引發。 在這裡,我們可以判斷使用者是否已達到「完成」步驟;如果是,我們需要將使用者新增至選取的角色。
建立 事件的事件處理常式 ActiveStepChanged
,並新增下列程式碼:
Protected Sub RegisterUserWithRoles_ActiveStepChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles RegisterUserWithRoles.ActiveStepChanged
'Have we JUST reached the Complete step?
If RegisterUserWithRoles.ActiveStep.Title = "Complete" Then
' Reference the SpecifyRolesStep WizardStep
Dim SpecifyRolesStep As WizardStep = CType(RegisterUserWithRoles.FindControl("SpecifyRolesStep"),WizardStep)
' Reference the RoleList CheckBoxList
Dim RoleList As CheckBoxList = CType(SpecifyRolesStep.FindControl("RoleList"), CheckBoxList)
' Add the checked roles to the just-added user
For Each li As ListItem In RoleList.Items
If li.Selected Then
Roles.AddUserToRole(RegisterUserWithRoles.UserName, li.Text)
End If
Next
End If
End Sub
如果使用者剛到達 「已完成」步驟,事件處理常式會列舉 CheckBoxList 的專案 RoleList
,並將剛建立的使用者指派給選取的角色。
透過瀏覽器流覽此頁面。 CreateUserWizard 中的第一個步驟是標準「註冊新帳戶」步驟,它會提示新使用者的使用者名稱、密碼、電子郵件和其他金鑰資訊。 輸入資訊以建立名為 Wanda 的新使用者。
圖 12:建立名為 Wanda 的新使用者 (按一下即可檢視完整大小的映射)
按一下 [建立使用者] 按鈕。 CreateUserWizard 會在內部呼叫 Membership.CreateUser
方法、建立新的使用者帳戶,然後繼續進行下一個步驟「指定角色」。此處列出系統角色。 核取 [監督員] 核取方塊,然後按 [下一步]。
圖 13:將 Wanda 設為監督員角色的成員 (按一下即可檢視全大小影像)
按 [下一步] 會導致回傳,並將 更新 ActiveStep
為 「完成」步驟。 在 ActiveStepChanged
事件處理常式中,最近建立的使用者帳戶會指派給監督員角色。 若要確認這一點,請返回 UsersAndRoles.aspx
頁面,然後從 RoleList
DropDownList 選取 [監督員]。 如圖 14 所示,監督員現在由三個使用者組成:Bruce、Tito 和 Wanda。
圖 14:Bruce、Tito 和 Wanda 是 [所有監督員] (按一下即可檢視完整大小的影像)
摘要
角色架構提供方法來擷取特定使用者角色的相關資訊,以及判斷使用者屬於指定角色的方法。 此外,還有一些方法可將一或多個使用者新增和移除至一或多個角色。 在本教學課程中,我們只著重于下列兩種方法: AddUserToRole
和 RemoveUserFromRole
。 另外還有一些變體,其設計目的是要將多個使用者新增至單一角色,以及將多個角色指派給單一使用者。
本教學課程也包含擴充 CreateUserWizard 控制項,以包含 WizardStep
以指定新建立使用者的角色。 這類步驟可協助系統管理員簡化為新使用者建立使用者帳戶的程式。
此時,我們已瞭解如何建立和刪除角色,以及如何新增和移除角色中的使用者。 但我們尚未探討如何套用以角色為基礎的授權。 在下列教學 課程中,我們將探討以角色為基礎定義 URL 授權規則,以及如何根據目前登入的使用者角色來限制頁面層級功能。
快樂的程式設計!
深入閱讀
如需本教學課程中所討論之主題的詳細資訊,請參閱下列資源:
關於作者
Scott Mitchell 是多個 ASP/ASP.NET 書籍的作者,且 4GuysFromRolla.com 的作者,自 1998 年以來,已與 Microsoft Web 技術合作。 Scott 是獨立顧問、訓練員和作者。 他的最新書籍是 Sams 在 24 小時內自行 ASP.NET 2.0。 您可以在 或 透過在 的 http://ScottOnWriting.NET 部落格連線 mitchell@4guysfromrolla.com 到 Scott。
特別感謝...
本教學課程系列是由許多實用的檢閱者檢閱。 本教學課程的首席檢閱者是 Teresa Murphy。 有興趣檢閱即將推出的 MSDN 文章嗎? 如果是,請將一行放在我 mitchell@4GuysFromRolla.com