向用户分配角色 (VB)
注意
自本文撰写以来,ASP.NET 成员资格提供程序已被 ASP.NET Identity 取代。 强烈建议更新应用以使用 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
中继器。 此中继器将系统中的所有角色作为一系列复选框列出。 使用以下声明性标记定义中继器 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
因为 Roles 框架将角色名称列表作为字符串数组返回,而我们将绑定到 Repeater 的正是此字符串数组。 有关为何使用此语法显示绑定到数据 Web 控件的数组内容的完整说明超出了本教程的范围。 有关此问题的详细信息,请参阅将 标量数组绑定到数据 Web 控件。
此时,“by user”接口的声明性标记应如下所示:
<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,并将角色集绑定到中继器。 在页面的代码隐藏类中,使用以下代码添加名为 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
方法,该方法返回一个字符串数组,其中包含系统中的角色。 然后,此字符串数组绑定到中继器。
最后,我们需要在首次加载页面时调用这两种方法。 将以下代码添加到 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。 所有用户帐户都填充在下拉列表中,并在该列表中,每个角色都显示为复选框。 由于我们将 DropDownList 和 CheckBoxes 的属性设置为 AutoPostBack
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)
方法 将指定用户的角色集作为字符串数组返回。 接下来,枚举 Repeater 的项,并且以编程方式引用每个项的 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
需要在两种情况下调用 方法:首次加载页面时和 DropDownList UserList
的选定索引发生更改时。 因此,在调用 和 BindRolesToList
) 后,从Page_Load
事件处理程序 (调用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
表中来手动将用户添加到角色,以便立即测试此功能。
分配和删除角色中的用户
当访问者在 Repeater 中 UsersRoleList
检查或取消选中 CheckBox 时,我们需要在相应的角色中添加或删除所选用户。 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,我们通过 类的 AddUserToRole
或 RemoveUserFromRole
方法在角色Roles
中添加或删除用户。
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 已添加到管理员和主管角色 (单击以查看全尺寸图像)
接下来,从下拉列表中选择“用户 Bruce”。 有回发,中继器的 CheckBox 通过 CheckRolesForSelectedUser
更新。 由于 Bruce 尚不属于任何角色,因此取消选中这两个复选框。 接下来,将 Bruce 添加到“主管”角色。
图 4:Bruce 已添加到主管角色 (单击以查看全尺寸图像)
若要进一步验证方法的功能 CheckRolesForSelectedUser
,请选择 Tito 或 Bruce 以外的用户。 请注意复选框如何自动取消选中,表示它们不属于任何角色。 返回到 Tito。 应选中“管理员”和“主管”复选框。
步骤 2:生成“按角色”用户界面
此时,我们已经完成了“按用户”界面,并已准备好开始处理“按角色”接口。 “按角色”界面提示用户从下拉列表中选择一个角色,然后在 GridView 中显示属于该角色的用户集。
将另一个 DropDownList 控件添加到 。UsersAndRoles.aspx page
将此名称放在 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
方法,以便将 该方法RolesList
返回的Roles.GetAllRoles
字符串数组绑定到 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
此方法首先从 DropDownList 获取 RoleList
所选角色。 然后,Roles.GetUsersInRole(roleName)
它使用 方法检索属于该角色的用户的 UserNames 的字符串数组。 然后,此数组将绑定到 RolesUserList
GridView。
需要在两种情况下调用此方法:最初加载页面时和 DropDownList 中 RoleList
所选角色发生更改时。 因此,请 Page_Load
更新事件处理程序,以便在调用 CheckRolesForSelectedUser
后调用此方法。 接下来,为 RoleList
的 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()
'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:唉, Tito 不再是主管 (单击以查看全尺寸图像)
将新用户添加到所选角色
除了从所选角色中删除用户外,此页面的访问者还应能够将用户添加到所选角色。 将用户添加到所选角色的最佳界面取决于预期拥有的用户帐户数。 如果你的网站只包含几十个或更少的用户帐户,则可以在此处使用 DropDownList。 如果可能有数千个用户帐户,则你需要包含一个用户界面,该用户界面允许访问者翻页浏览帐户、搜索特定帐户或以某种其他方式筛选用户帐户。
对于此页面,我们将使用一个非常简单的界面,无论系统中的用户帐户数如何,它都能正常工作。 也就是说,我们将使用 TextBox,提示访问者键入要添加到所选角色的用户的用户名。 如果不存在具有该名称的用户,或者用户已是该角色的成员,我们将在 Label 中 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>
接下来,为 AddUserToRoleButton
创建Click
事件处理程序,并添加以下代码:
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
将显示一条消息,指示指定用户已成功添加到所选角色。
注意
为了确保指定的用户不属于所选角色,我们使用 Roles.IsUserInRole(userName, roleName)
方法,该方法返回一个布尔值,指示 userName 是否是 roleName 的成员。 在下一教程中,我们将再次使用此方法,了解基于角色的授权。
通过浏览器访问页面,并从 RoleList
DropDownList 中选择“主管”角色。 尝试输入无效的用户名 - 应会看到一条消息,说明系统中不存在该用户。
图 9:无法将不存在的用户添加到角色 (单击以查看全尺寸图像)
现在,请尝试添加有效用户。 继续将 Tito 重新添加到“主管”角色。
图 10:蒂托再次成为主管! (单击以查看全尺寸图像)
步骤 3:交叉更新“按用户”和“按角色”接口
该 UsersAndRoles.aspx
页面提供了两个不同的界面,用于管理用户和角色。 目前,这两个接口彼此独立,因此在一个接口中所做的更改可能不会立即反映在另一个接口中。 例如,假设页面访问者从 RoleList
DropDownList 中选择“主管”角色,该角色将 Bruce 和 Tito 列为其成员。 接下来,访问者从 UserList
DropDownList 中选择 Tito,这将检查中继器中的 UsersRoleList
“管理员”和“监督者”复选框。 如果访问者随后从中继器中取消选中“监督器”角色,则 Tito 将从“主管”角色中删除,但此修改不会反映在“按角色”接口中。 GridView 仍会将 Tito 显示为“主管”角色的成员。
若要解决此问题,每当在中继器中选中或取消选中 UsersRoleList
某个角色时,都需要刷新 GridView。 同样,每当从“按角色”界面删除或将用户添加到角色时,我们需要刷新中继器。
通过调用 CheckRolesForSelectedUser
方法刷新“by user”界面中的中继器。 可以在 GridView 的RowDeleting
事件处理程序和 AddUserToRoleButton
Button Click
的事件处理程序中RolesUserList
修改“按角色”接口。 因此,我们需要从其中每个方法调用 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
Supervisors。 请注意,从“用户”界面的中继器中取消选中 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
属性设置为“指定角色”,将其 StepType
属性设置为 Step
,将其 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.
“此 CheckBoxList”的 CheckBoxList 将列出可用角色,使访问页面的人员能够检查新创建的用户所属的角色。
我们还有两个编码任务:首先,必须使用系统中的角色填充 RoleList
CheckBoxList;第二,当用户从“指定角色”步骤移动到“完成”步骤时,需要将创建的用户添加到所选角色。 我们可以在事件处理程序中 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:使万达成为主管角色的成员 (单击以查看全尺寸图像)
单击“下一步”会导致回发, ActiveStep
并将 更新为“完成”步骤。 在 ActiveStepChanged
事件处理程序中,将最近创建的用户帐户分配给“监督员”角色。 若要验证这一点,请返回到页面, UsersAndRoles.aspx
然后从 RoleList
DropDownList 中选择“监督器”。 如图 14 所示,主管现在由三个用户组成:布鲁斯、蒂托和万达。
图 14:布鲁斯、蒂托和万达都是主管 (单击查看全尺寸图像)
摘要
角色框架提供用于检索特定用户角色信息的方法,以及用于确定哪些用户属于指定角色的方法。 此外,有多种方法可用于向一个或多个角色添加和删除一个或多个用户。 在本教程中,我们仅重点介绍以下两种方法: AddUserToRole
和 RemoveUserFromRole
。 其他变体旨在将多个用户添加到单个角色,并将多个角色分配给单个用户。
本教程还介绍了如何扩展 CreateUserWizard 控件以包含 以 WizardStep
指定新创建用户的角色。 此步骤可帮助管理员简化为新用户创建用户帐户的过程。
此时,我们已了解如何创建和删除角色,以及如何在角色中添加和删除用户。 但是,我们尚未研究如何应用基于角色的授权。 在以下 教程中 ,我们将介绍如何按角色定义 URL 授权规则,以及如何根据当前登录用户的角色限制页面级功能。
编程快乐!
深入阅读
有关本教程中讨论的主题的详细信息,请参阅以下资源:
关于作者
Scott Mitchell 是多本 ASP/ASP.NET 书籍的作者和 4GuysFromRolla.com 的创始人,自 1998 年以来一直从事 Microsoft Web 技术工作。 Scott 担任独立顾问、培训师和作家。 他的最新一本书是 山姆斯在 24 小时内 ASP.NET 2.0。 可以在 上联系 mitchell@4guysfromrolla.com 斯科特,也可以通过他的博客在 联系 http://ScottOnWriting.NET。
特别感谢...
本教程系列由许多有用的审阅者审阅。 本教程的首席审阅者是 Teresa Murphy。 有兴趣查看我即将发布的 MSDN 文章? 如果是这样,请在 mitchell@4GuysFromRolla.com