Назначение ролей пользователям (C#)

Скотт Митчелл

Примечание

С момента написания этой статьи поставщики членства ASP.NET были заменены ASP.NET Identity. Мы настоятельно рекомендуем обновить приложения для использования платформы ASP.NET Identity , а не поставщиков членства, которые были представлены на момент написания этой статьи. ASP.NET Identity имеет ряд преимуществ по сравнению с системой членства ASP.NET, включая :

  • более высокая производительность;
  • Улучшенная расширяемость и тестируемость
  • Поддержка OAuth, OpenID Connect и двухфакторной проверки подлинности
  • Поддержка удостоверений на основе утверждений
  • Улучшенное взаимодействие с ASP.Net Core

Скачать код или скачать PDF-файл

В этом руководстве мы создадим две страницы ASP.NET, которые помогут управлять пользователями, принадлежащими к тем или иным ролям. Первая страница содержит средства, которые позволяют узнать, какие пользователи принадлежат к определенной роли, к каким ролям принадлежит конкретный пользователь, а также возможность назначить или удалить определенного пользователя из определенной роли. На второй странице мы добавим элемент управления CreateUserWizard, чтобы он включает шаг для указания ролей, к которым принадлежит только что созданный пользователь. Это полезно в сценариях, когда администратор может создавать новые учетные записи пользователей.

Введение

В предыдущем руководстве рассматривались платформа Roles и SqlRoleProvider; мы узнали Roles , как использовать класс для создания, извлечения и удаления ролей. Помимо создания и удаления ролей, необходимо иметь возможность назначать или удалять пользователей из роли. К сожалению, ASP.NET не поставляются с веб-элементами управления для управления пользователями, принадлежащими к тем или иным ролям. Вместо этого мы должны создать собственные страницы ASP.NET для управления этими связями. Хорошей новостью является то, что добавлять и удалять пользователей в роли довольно просто. Класс Roles содержит несколько методов для добавления одного или нескольких пользователей в одну или несколько ролей.

В этом руководстве мы создадим две страницы ASP.NET, которые помогут управлять пользователями, принадлежащими к тем или иным ролям. Первая страница содержит средства, которые позволяют узнать, какие пользователи принадлежат к определенной роли, к каким ролям принадлежит конкретный пользователь, а также возможность назначить или удалить определенного пользователя из определенной роли. На второй странице мы добавим элемент управления CreateUserWizard, чтобы он включает шаг для указания ролей, к которым принадлежит только что созданный пользователь. Это полезно в сценариях, когда администратор может создавать новые учетные записи пользователей.

Приступим к работе!

Список пользователей, принадлежащих к тем или иным ролям

Первым делом в этом руководстве следует создать веб-страницу, на которой пользователям могут быть назначены роли. Прежде чем мы рассмотрим, как назначать пользователям роли, давайте сначала сосредоточимся на том, как определить, какие пользователи принадлежат к тем или иным ролям. Существует два способа отображения этой информации: "по роли" или "по пользователю". Мы можем разрешить посетителю выбрать роль, а затем показать ему всех пользователей, принадлежащих к роли (отображение "по роли"), или предложить посетителю выбрать пользователя, а затем показать ему роли, назначенные ему (отображение "по пользователю").

Представление "по роли" полезно в тех случаях, когда посетитель хочет узнать набор пользователей, принадлежащих к определенной роли; Представление "по пользователю" идеально подходит, когда посетителю необходимо знать роли конкретного пользователя. Давайте добавим, что наша страница содержит интерфейсы "по роли" и "по пользователю".

Начнем с создания интерфейса "по пользователю". Этот интерфейс будет состоять из раскрывающегося списка и списка флажков. Раскрывающийся список будет заполнен набором пользователей в системе; флажки будут перечислять роли. При выборе пользователя из раскрывающегося списка будут проверка роли, к которой он принадлежит. Пользователь, посещающий страницу, может проверка или снять флажки, чтобы добавить или удалить выбранного пользователя из соответствующих ролей.

Примечание

Использование раскрывающегося списка для перечисления учетных записей пользователей не является идеальным выбором для веб-сайтов, где могут быть сотни учетных записей пользователей. Раскрывающийся список позволяет пользователю выбрать один элемент из относительно короткого списка параметров. Он быстро становится громоздким по мере роста количества элементов списка. Если вы создаете веб-сайт, который будет иметь потенциально большое количество учетных записей пользователей, вы можете рассмотреть возможность использования альтернативного пользовательского интерфейса, например страничного GridView или фильтруемого интерфейса, который предлагает посетителю выбрать букву, а затем отображает только тех пользователей, имя пользователя которых начинается с выбранной буквы.

Шаг 1. Создание пользовательского интерфейса "По пользователю"

Откройте страницу UsersAndRoles.aspx . В верхней части страницы добавьте веб-элемент управления Label с именем ActionStatus и очистите его Text свойство. Мы будем использовать эту метку, чтобы оставить отзыв о выполненных действиях, отображая такие сообщения, как "Пользователь Тито был добавлен в роль администраторов" или "Пользователь Jisun был удален из роли "Супервизоры". Чтобы выделить эти сообщения, задайте для свойства Label CssClass значение "Важно".

<p align="center"> 

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

Затем добавьте в таблицу стилей следующее Styles.css определение класса CSS:

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

Это определение CSS предписывает браузеру отобразить метку с помощью большого красного шрифта. На рисунке 1 показан этот эффект с помощью Designer Visual Studio.

Свойство CssClass метки приводит к большому красному шрифту

Рис. 1. Свойство метки CssClass приводит к большому красному шрифту (щелкните для просмотра полноразмерного изображения)

Затем добавьте dropDownList на страницу, присвойте свойству IDUserListзначение , а свойству — AutoPostBack значение True. Мы будем использовать этот список DropDownList для вывода списка всех пользователей в системе. Этот DropDownList будет привязан к коллекции объектов MembershipUser. Так как мы хотим, чтобы DropDownList отображал свойство UserName объекта MembershipUser (и использовал его в качестве значения элементов списка), задайте для свойств 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 включает в себя один веб-элемент управления CheckBox с именем RoleCheckBox. Свойство CheckBox AutoPostBack имеет значение True, а Text свойство привязано к Container.DataItem. Причина синтаксиса привязки данных заключается в том, Container.DataItem что платформа ролей возвращает список имен ролей в виде массива строк, и именно этот массив строк будет привязан к Repeater. Подробное описание того, почему этот синтаксис используется для отображения содержимого массива, привязанного к веб-элементу управления данными, выходит за рамки область этого руководства. Дополнительные сведения по этому вопросу см. в статье Привязка скалярного массива к веб-элементу управления данных.

На этом этапе декларативная разметка интерфейса "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 и набора ролей к 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 , которые содержат коллекцию, содержат различные свойства, такие как UserName, Email, CreationDateи IsOnline. Чтобы указать DropDownList отобразить значение UserName свойства, убедитесь, что UserList свойства DropDownList DataTextField и DataValueField имеют значение 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 и CheckBoxes задано 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; 
     } 
}

Приведенный выше код начинается с определения выбранного пользователя. Затем он использует метод класса GetRolesForUser(userName) Roles для возврата набора ролей указанного пользователя в виде массива строк. Далее перечисляются элементы Repeater, и на элемент CheckBox каждого элемента RoleCheckBox создается программная ссылка. Флажок CheckBox проверяется только в том случае, если роль, которая ему соответствует, содержится в массиве selectedUsersRoles строк.

Примечание

Синтаксис selectedUserRoles.Contains<string>(...) не будет компилироваться, если используется ASP.NET версии 2.0. Метод Contains<string> является частью библиотеки LINQ, которая является новой для ASP.NET 3.5. Если вы по-прежнему используете ASP.NET версии 2.0, используйте Array.IndexOf<string> метод .

Метод CheckRolesForSelectedUser необходимо вызывать в двух случаях: при первой загрузке страницы и при изменении выбранного UserList индекса DropDownList. Поэтому вызовите этот метод из обработчика Page_Load событий (после вызовов BindUsersToUserList и BindRolesToList). Кроме того, создайте обработчик событий для события 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 repeater, необходимо добавить или удалить выбранного пользователя из соответствующей роли. Свойство CheckBox AutoPostBack в настоящее время имеет значение True, что приводит к обратной отправке при каждом снятии флажка CheckBox в повторителе. Короче говоря, нам нужно создать обработчик событий для события CheckBox CheckChanged . Так как CheckBox находится в элементе управления Repeater, необходимо вручную добавить сантехнику обработчика событий. Начните с добавления обработчика событий в класс кода программной части в protected качестве метода следующим образом:

protected void RoleCheckBox_CheckChanged(object sender, EventArgs e) 
{ 

}

Мы вернемся к написанию кода для этого обработчика событий через некоторое время. Но сначала давайте завершим обработку событий сантехники. Из checkBox в элементе Repeater добавьте ItemTemplateOnCheckedChanged="RoleCheckBox_CheckChanged". Этот синтаксис подключает RoleCheckBox_CheckChanged обработчик событий к событию RoleCheckBoxCheckedChanged .

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

Последняя задача — завершить RoleCheckBox_CheckChanged обработчик событий. Для начала необходимо сослаться на элемент управления CheckBox, который вызвал событие, так как этот экземпляр CheckBox сообщает нам, какая роль была проверена или снята с помощью свойств Text и Checked . Используя эти сведения вместе с именем пользователя выбранного пользователя, мы добавляем или удаляем пользователя из роли с помощью Roles метода или RemoveUserFromRoleкласса AddUserToRole .

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 в роли Администраторы и Супервизоры.

Тито добавлен в роли администраторов и руководителей

Рис. 3. Тито добавлен в роли администраторов и руководителей (щелкните, чтобы просмотреть полноразмерное изображение)

Затем выберите пользователя Брюса из раскрывающегося списка. Существует обратная связь, и checkBox repeater обновляется с помощью CheckRolesForSelectedUser. Так как Брюс еще не принадлежит ни к одной роли, два флажка сняты. Затем добавьте Брюса в роль "Супервизоры".

Брюс добавлен в роль

Рис. 4. Брюс добавлен в роль "Супервизоры" (щелкните для просмотра полноразмерного изображения)

Чтобы дополнительно проверить функциональность метода, выберите пользователя, отличного CheckRolesForSelectedUser от Тито или Брюса. Обратите внимание, что флажки автоматически сняты, указывая, что они не принадлежат ни к одной роли. Вернитесь к Тито. Установите флажки Администраторы и Супервизоры.

Шаг 2. Создание пользовательского интерфейса "По ролям"

На этом этапе мы завершили работу с интерфейсом "по пользователям" и готовы приступить к работе с интерфейсом "по ролям". Интерфейс "по ролям" предлагает пользователю выбрать роль из раскрывающегося списка, а затем отображает набор пользователей, принадлежащих к этой роли, в GridView.

Добавьте на страницу UsersAndRoles.aspx еще один элемент управления DropDownList. Поместите его под элементом управления Repeater, назовите его RoleListи задайте для его AutoPostBack свойства значение True. Под этим элементом добавьте GridView и назовите его RolesUserList. Этот элемент GridView выводит список пользователей, принадлежащих к выбранной роли. Задайте для свойства GridView AutoGenerateColumns значение False, добавьте TemplateField в коллекцию сетки Columns и задайте для его HeaderText свойства значение Users. Определите свойство TemplateField таким ItemTemplate образом, чтобы оно отображало значение выражения Container.DataItem привязки данных в Text свойстве объекта Label с именем UserNameLabel.

После добавления и настройки 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

Рис. 5. Роли отображаются в RoleList раскрывающемся списке (щелкните, чтобы просмотреть полноразмерное изображение)

Отображение пользователей, принадлежащих к выбранной роли

При первой загрузке страницы или при выборе новой роли в RoleList Раскрывающемся списке необходимо отобразить список пользователей, принадлежащих этой роли, в 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(); 
}

Этот метод начинается с получения выбранной роли из RoleList DropDownList. Затем он использует Roles.GetUsersInRole(roleName) метод для получения массива строк UserNames пользователей, принадлежащих к этой роли. Затем этот массив привязывается к RolesUserList GridView.

Этот метод необходимо вызывать в двух случаях: при первоначальной загрузке страницы и при изменении выбранной роли в Раскрывающемся RoleList списке. Поэтому обновите Page_Load обработчик событий так, чтобы этот метод вызывался после вызова CheckRolesForSelectedUserметода . Затем создайте обработчик событий для RoleListSelectedIndexChanged события и вызовите этот метод.

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, роль "Руководители" состоит из двух членов: Брюса и Тито.

GridView выводит список пользователей, принадлежащих к выбранной роли

Рис. 6. GridView выводит список пользователей, принадлежащих к выбранной роли (щелкните для просмотра полноразмерного изображения)

Удаление пользователей из выбранной роли

Давайте добавим RolesUserList GridView, чтобы он был включен в столбец кнопок "Удалить". Нажатие кнопки "Удалить" для определенного пользователя приведет к удалению его из этой роли.

Начните с добавления поля кнопки Удалить в GridView. Сделайте это поле наиболее левым и измените его DeleteText свойство с "Delete" (по умолчанию) на "Удалить".

Снимок экрана: добавление кнопки

Рис. 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 элемент управления из строки, для которой была нажата кнопка "Удалить", чтобы определить имя пользователя, удаляемого пользователя. Затем пользователь удаляется из роли с помощью вызова Roles.RemoveUserFromRole метода . Затем RolesUserList GridView обновляется, и сообщение отображается с помощью ActionStatus элемента управления Метка.

Примечание

Кнопка "Удалить" не требует подтверждения от пользователя перед удалением пользователя из роли. Я приглашаю вас добавить некоторый уровень подтверждения пользователя. Одним из самых простых способов подтверждения действия является диалоговое окно подтверждения на стороне клиента. Дополнительные сведения об этом методе см. в разделе Добавление подтверждения Client-Side при удалении.

На рисунке 8 показана страница после удаления пользователя Tito из группы "Супервизоры".

Увы, Тито больше не является руководителем

Рис. 8. Увы, Тито больше не является руководителем (щелкните для просмотра полноразмерного изображения)

Добавление новых пользователей в выбранную роль

Наряду с удалением пользователей из выбранной роли посетитель этой страницы также должен иметь возможность добавить пользователя в выбранную роль. Оптимальный интерфейс для добавления пользователя к выбранной роли зависит от ожидаемого количества учетных записей пользователей. Если на вашем веб-сайте будет размещено всего несколько десятков учетных записей пользователей или меньше, вы можете использовать DropDownList здесь. Если могут быть тысячи учетных записей пользователей, необходимо включить пользовательский интерфейс, который позволяет посетителю просматривать страницы учетных записей, искать определенную учетную запись или фильтровать учетные записи пользователей другим способом.

Для этой страницы мы используем очень простой интерфейс, который работает независимо от количества учетных записей пользователей в системе. А именно, мы будем использовать элемент TextBox, предлагающий посетителю ввести имя пользователя, которого он хочет добавить в выбранную роль. Если нет пользователя с таким именем или пользователь уже является членом роли, мы выведем сообщение в ActionStatus label. Но если пользователь существует и не является членом роли, мы добавим его в роль и обновим сетку.

Добавьте textBox и Button под GridView. Задайте для элемента TextBox ID значение UserNameToAddToRole , а свойства AddUserToRoleButton и Button IDText — значение и "Добавить пользователя в роль" соответственно.

<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 событий выполняет различные проверки. Это гарантирует, что посетитель предоставил имя пользователя в UserNameToAddToRole TextBox, что пользователь существует в системе и что он еще не принадлежит к выбранной роли. Если какая-либо из этих проверок завершается сбоем, отображается ActionStatus соответствующее сообщение и обработчик событий завершается. Если все проверки пройдены, пользователь добавляется в роль с помощью Roles.AddUserToRole метода . После этого свойство TextBox Text очищается, GridView обновляется, а в ActionStatus поле Метка отображается сообщение о том, что указанный пользователь успешно добавлен в выбранную роль.

Примечание

Чтобы убедиться, что указанный пользователь еще не принадлежит выбранной роли, мы используем Roles.IsUserInRole(userName, roleName) метод , который возвращает логическое значение, указывающее, является ли userName членом roleName. Мы снова будем использовать этот метод в следующем руководстве, когда мы рассмотрим авторизацию на основе ролей.

Перейдите на страницу в браузере и выберите роль "Руководители" в раскрывающемся RoleList списке. Попробуйте ввести недопустимое имя пользователя. Вы увидите сообщение о том, что пользователь не существует в системе.

Невозможно добавить несуществующего пользователя в роль

Рис. 9. Невозможно добавить несуществующего пользователя в роль (щелкните для просмотра полноразмерного изображения)

Теперь попробуйте добавить допустимого пользователя. Добавьте Тито в роль "Руководители".

Тито снова руководитель!

Рис. 10. Тито снова руководитель! (Щелкните для просмотра полноразмерного изображения)

Шаг 3. Перекрестное обновление интерфейсов "По пользователю" и "По роли"

Страница UsersAndRoles.aspx предлагает два различных интерфейса для управления пользователями и ролями. В настоящее время эти два интерфейса действуют независимо друг от друга, поэтому возможно, что изменения, внесенные в одном интерфейсе, не будут отражены сразу в другом. Например, представьте, что посетитель страницы выбирает роль "Руководители" в RoleList раскрывающемся списке, в котором в качестве участников указаны Брюс и Тито. Затем посетитель выбирает Tito в UserList раскрывающемся списке, который устанавливает флажки Администраторы и Руководители в ретрансляторе UsersRoleList . Если посетитель снимет флажок "Супервайзер" в ретрансляторе, Тито удаляется из роли "Руководители", но это изменение не отражается в интерфейсе "по ролям". GridView по-прежнему будет отображать Тито как члена роли "Руководители".

Чтобы устранить эту проблему, необходимо обновлять GridView всякий раз, когда роль проверяется или снята с ретранслятора UsersRoleList . Аналогичным образом необходимо обновлять repeater всякий раз, когда пользователь удаляется или добавляется к роли из интерфейса "по роли".

Repeater в интерфейсе "by user" обновляется путем вызова CheckRolesForSelectedUser метода . Интерфейс "по роли" можно изменить в RolesUserList обработчике RowDeleting событий GridView и AddUserToRoleButton обработчике Click событий Button. Поэтому необходимо вызвать 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(); 
}

Аналогичным образом GridView в интерфейсе "по роли" обновляется путем вызова DisplayUsersBelongingToRole метода , а интерфейс "по пользователю" изменяется с помощью обработчика RoleCheckBox_CheckChanged событий. Поэтому необходимо вызвать DisplayUsersBelongingToRole метод из этого обработчика событий.

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

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

С этими незначительными изменениями кода интерфейсы "по пользователю" и "по роли" теперь правильно перекрестно обновляются. Чтобы проверить это, перейдите на страницу в браузере и выберите Tito и Супервизоры в UserList раскрывающихся списках и RoleList соответственно. Обратите внимание, что при снятии флажка Роли "Руководители" для Tito в ретрансляторе в интерфейсе "по пользователю" Tito автоматически удаляется из GridView в интерфейсе "по роли". При добавлении Тито обратно в роль "Руководители" из интерфейса "по роли" автоматически проверяется флажок "Руководители" в интерфейсе "по пользователю".

Шаг 4. Настройка шага CreateUserWizard для включения шага "Указание ролей"

В учебнике Создание учетных записей пользователей мы узнали, как использовать веб-элемент управления CreateUserWizard для предоставления интерфейса для создания новой учетной записи пользователя. Элемент управления CreateUserWizard можно использовать одним из двух способов:

  • В качестве средства для посетителей, чтобы создать собственную учетную запись пользователя на сайте, и
  • Как средство для создания новых учетных записей администраторами

В первом случае использования посетитель приходит на сайт и заполняет CreateUserWizard, вводя свои данные для регистрации на сайте. Во втором случае администратор создает новую учетную запись для другого пользователя.

Если учетная запись создается администратором для другого пользователя, может быть полезно разрешить администратору указать, к каким ролям принадлежит новая учетная запись пользователя. В руководстве По хранению дополнительных сведений о пользователе мы узнали, как настроить CreateUserWizard путем добавления дополнительных сведений WizardSteps. Давайте рассмотрим, как добавить дополнительный шаг в CreateUserWizard, чтобы указать роли нового пользователя.

Откройте страницу CreateUserWizardWithRoles.aspx и добавьте элемент управления CreateUserWizard с именем RegisterUserWithRoles. Задайте для свойства элемента управления ContinueDestinationPageUrl значение "~/Default.aspx". Так как идея заключается в том, что администратор будет использовать этот элемент управления CreateUserWizard для создания новых учетных записей пользователей, присвойте LoginCreatedUser свойству элемента управления значение False. Это LoginCreatedUser свойство указывает, будет ли посетитель автоматически входить в систему как только что созданный пользователь, и по умолчанию используется значение True. Мы устанавливаем для него значение False, так как когда администратор создает новую учетную запись, мы хотим, чтобы он вошел в систему как сам.

Затем выберите "Добавить или удалить WizardSteps..." параметр из смарт-тега CreateUserWizard и добавьте новый WizardStep, задав для нее ID значение SpecifyRolesStep. SpecifyRolesStep WizardStep Переместите , чтобы он был выполнен после шага "Регистрация для новой учетной записи", но до шага "Завершить". Присвойте Title свойству WizardStepзначение "Указать роли", свойству StepTypeStep— значение , а свойству 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добавьте элемент CheckBoxList с именем RoleList. Этот элемент CheckBoxList выводит список доступных ролей, позволяя пользователю, посещающему страницу, проверка, к каким ролям принадлежит только что созданный пользователь.

Осталось выполнить две задачи программирования: во-первых, необходимо заполнить RoleList CheckBoxList ролями в системе; во-вторых, необходимо добавить созданного пользователя к выбранным ролям при переходе пользователя с шага "Указание ролей" на шаг "Завершить". Мы можем выполнить первую задачу в обработчике 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. Код, который привязывает роли к 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); 
          } 
     } 
}

Если пользователь только что достиг шага "Завершено", обработчик событий перечисляет элементы RoleList CheckBoxList и только что созданному пользователю назначается выбранные роли.

Посетите эту страницу в браузере. Первым шагом в CreateUserWizard является стандартный шаг "Регистрация для новой учетной записи", который запрашивает имя пользователя, пароль, адрес электронной почты и другие ключевые сведения нового пользователя. Введите сведения для создания нового пользователя С именем Wanda.

Создание пользователя С именем Wanda

Рис. 12. Создание пользователя с именем Wanda (щелкните, чтобы просмотреть изображение в полном размере)

Нажмите кнопку "Создать пользователя". CreateUserWizard внутренне вызывает Membership.CreateUser метод , создавая новую учетную запись пользователя, а затем переходит к следующему шагу , "Укажите роли". Здесь перечислены системные роли. Установите флажок Руководители и нажмите кнопку Далее.

Назначение Ванда членом роли руководителей

Рис. 13. Назначение Wanda членом роли "Руководители" (щелкните для просмотра полноразмерного изображения)

При нажатии кнопки Далее происходит обратная связь и выполняется обновление ActiveStep до шага "Завершить". В обработчике ActiveStepChanged событий недавно созданной учетной записи пользователя назначается роль "Руководители". Чтобы убедиться в этом, вернитесь на страницу UsersAndRoles.aspx и выберите "Супервизоры" в RoleList раскрывающемся списке. Как показано на рисунке 14, руководители теперь состоят из трех пользователей: Брюса, Тито и Ванда.

Брюс, Тито и Ванда все руководители

Рис. 14. Брюс, Тито и Ванда — все руководители (щелкните для просмотра полноразмерного изображения)

Сводка

Платформа ролей предлагает методы для получения сведений о ролях конкретного пользователя и методы определения того, какие пользователи принадлежат указанной роли. Кроме того, существует ряд методов добавления и удаления одного или нескольких пользователей в одну или несколько ролей. В этом руководстве мы сосредоточились только на двух из этих методов: AddUserToRole и RemoveUserFromRole. Существуют дополнительные варианты, предназначенные для добавления нескольких пользователей к одной роли и назначения нескольких ролей одному пользователю.

В этом руководстве также рассматривается расширение элемента управления CreateUserWizard, чтобы включить для WizardStep указания ролей только что созданных пользователей. Такой шаг поможет администратору упростить процесс создания учетных записей пользователей для новых пользователей.

На этом этапе мы видели, как создавать и удалять роли, а также как добавлять и удалять пользователей из ролей. Но нам еще предстоит рассмотреть применение авторизации на основе ролей. В следующем руководстве мы рассмотрим определение правил авторизации URL-адресов на основе ролей по ролям, а также об ограничении функциональных возможностей на уровне страницы на основе ролей вошедшего в систему пользователя.

Счастливого программирования!

Дополнительные материалы

Дополнительные сведения о темах, рассмотренных в этом руководстве, см. в следующих ресурсах:

Об авторе

Скотт Митчелл (Scott Mitchell), автор нескольких книг ASP/ASP.NET и основатель 4GuysFromRolla.com, работает с веб-технологиями Майкрософт с 1998 года. Скотт работает независимым консультантом, тренером и писателем. Его последняя книга Sams Teach Yourself ASP.NET 2.0 в 24 часа. Скотт можно связаться по адресу mitchell@4guysfromrolla.com или через его блог по адресу http://ScottOnWriting.NET.

Отдельная благодарность...

Эта серия учебников была проверена многими полезными рецензентами. Ведущим рецензентом этого руководства была Тереса Мерфи. Хотите ознакомиться с моими предстоящими статьями MSDN? Если да, бросить мне линию на mitchell@4GuysFromRolla.com