Класс Membership

162

В этой статье вы научитесь работе с лежащим в основе интерфейсом программирования членства, который используется всеми элементами управления и всей инфраструктурой Membership API. Вы убедитесь в том, что этот API-интерфейс прост. Он состоит из класса по имени Membership с набором свойств и методов, а также класса по имени MembershipUser, который инкапсулирует свойства отдельного пользователя. Методы класса Membership выполняют следующие фундаментальные операции:

Многие методы класса Membership принимают в качестве параметра экземпляр MembershipUser либо возвращают его или целую коллекцию экземпляров MembershipUser.

Например, извлекая пользователя с помощью метода Membership.GetUser(), устанавливая свойства экземпляра, после чего отправляя этот экземпляр методу UpdateUser() класса Membership, можно легко обновить свойства пользователя. Оба класса - Membership и MembershipUser - предоставляют необходимый уровень абстракции между поставщиком и приложением. Все, что делается с классом Membership, опирается на поставщика. Это значит, что замена поставщика членства никак не повлияет на приложение, если реализация поставщика членства полная и поддерживает все средства, предлагаемые базовым классом MembershipProvider.

Все классы, используемые в Membership API, определены в пространстве имен System.Web.Security. Класс Membership содержит множество статических методов и свойств. Ниже приведен обзор различных типов задач, которые можно решать с помощью класса Membership и связанных с ним классов, таких как MembershipUser.

Извлечение пользователей из хранилища

Первая задача, которую придется выполнять посредством класса Membership - извлечение отдельного пользователя и списка пользователей из хранилища информации о членстве. Для этой цели создается простая страница с элементом управления GridView для привязки списка пользователей:

<asp:GridView ID="GridView1" runat="server" 
	DataKeyNames="UserName" AutoGenerateColumns="false">
	<Columns>
	    <asp:BoundField DataField="UserName" HeaderText="Имя пользователя" />
	    <asp:BoundField DataField="Email" HeaderText="Email" />
	    <asp:BoundField DataField="CreationDate" HeaderText="Зарегистрирован" />
	    <asp:CommandField ShowSelectButton="true" />
	</Columns>
</asp:GridView>

Как видите, GridView определяет поле UserName как DataKeyName. Это позволяет обращаться к значению UserName текущего выбранного пользователя непосредственно через свойство SelectedValue элемента управления GridView. Поскольку большинство методов требуют имя пользователя для получения деталей, это очень удобно. Имея такую страницу, можно добавить следующий код в процедуру события Page_Load для загрузки пользователей из хранилища членства и привязки их к экранной таблице:

public partial class Restricted_SecurePage : System.Web.UI.Page
{
    MembershipUserCollection _MyUsers;

    protected void Page_Load(object sender, EventArgs e)
    {
        _MyUsers = Membership.GetAllUsers();
        GridView1.DataSource = _MyUsers;

        if (!this.IsPostBack)
        {
            GridView1.DataBind();
        }
    }
}

На рисунке ниже можно видеть приложение в действии:

Тестовое приложение управления пользователями в действии

Как видите, класс Membership включает метод GetAllUsers(), который возвращает экземпляр типа MembershipUserCollection. Эту коллекцию можно использовать подобно любой другой. Каждый ее элемент содержит все свойства одного пользователя. Таким образом, если нужно отобразить подробности о выбранном пользователе, понадобится просто добавить пару элементов управления для отображения содержимого выбранного пользователя на ранее созданной странице, как показано ниже:

<asp:GridView ID="GridView1" runat="server"
    OnSelectedIndexChanged="GridView1_SelectedIndexChanged">
    ...
</asp:GridView>
<br />
Выбранный пользователь:<br />
<table style="border: 1px solid blue">
	<tr>
	    <td>Имя:</td>
	    <td>
	        <asp:Label ID="UsernameLabel" runat="server" /></td>
	</tr>
	<tr>
	    <td>Email:</td>
	    <td>
	        <asp:TextBox ID="EmailText" runat="server" /></td>
	</tr>
	<tr>
	    <td>Секретный вопрос: </td>
	    <td>
	        <asp:Label ID="PwdQuestionLabel" runat="server" /></td>
	</tr>
	<tr>
	    <td>Последний раз заходил:</td>
	    <td>
	        <asp:Label ID="LastLoginLabel" runat="server" /></td>
	</tr>
	<tr>
	    <td>Комментарий:</td>
	    <td>
	        <asp:TextBox ID="CommentText" runat="server"
		TextMode="multiline" /></td>
	</tr>
	<tr>
	    <td>
	        <asp:CheckBox ID="IsApprovedCheck" runat="server" Text="Доступен" />
	    </td>
	    <td>
	        <asp:CheckBox ID="IsLockedOutCheck" runat="Server" Text="Заблокирован" />
	    </td>
	</tr>
</table>

Затем можно перехватить событие SelectedIndexChanged ранее добавленного элемента управления GridView для заполнения этих полей соответствующими значениями:

protected void GridView1_SelectedIndexChanged(object sender, EventArgs e)
{
	if (GridView1.SelectedIndex >= 0)
	{
	    MembershipUser Current = _MyUsers[(string)GridView1.SelectedValue];

	    UsernameLabel.Text = Current.UserName;
	    PwdQuestionLabel.Text = Current.PasswordQuestion;
	    LastLoginLabel.Text = Current.LastActivityDate.ToShortDateString();
	    EmailText.Text = Current.Email;
	    CommentText.Text = Current.Comment;
	    IsApprovedCheck.Checked = Current.IsApproved;
	    IsLockedOutCheck.Checked = Current.IsLockedOut;
	}
}

Объект MembershipCollection требует имени пользователя для прямого доступа к нему. Методы класса Membership, такие как GetUser(), также требуют имени пользователя. Таким образом, поле UserName используется как значение свойства DataKeyNames. Имея экземпляр MembershipUser, вы получаете доступ к свойствам пользователя обычным образом.

Подробная информация о пользователе

Обновление пользователей в хранилище

Обновлять информацию о пользователе в хранилище членства почти так же легко, как и извлекать ее оттуда. Как только получен экземпляр MembershipUser, сразу же можно обновлять его свойства, такие как адрес электронной почты или комментарии. Затем необходимо вызвать метод UpdateUser() класса Membership. Это можно сделать, расширив предыдущий код добавлением кнопки на страницу и вставкой следующего кода в обработчик ее события Click:

protected void ActionUpdateUser_Click(object sender, EventArgs e)
{
	if (GridView1.SelectedIndex >= 0)
	{
	    MembershipUser Current = _MyUsers[(string)GridView1.SelectedValue];

	    Current.Email = EmailText.Text;
	    Current.Comment = CommentText.Text;
	    Current.IsApproved = IsApprovedCheck.Checked;

	    Membership.UpdateUser(Current);

	    // Обновить GridView
	    GridView1.DataBind();
	} 
}

Метод UpdateUser просто принимает модифицированный экземпляр MembershipUser, который требуется обновить. Перед вызовом этого метода необходимо обновить свойства экземпляра. Однако существует одно исключение: свойство IsLockedOut не может быть установлено. Это свойство устанавливается автоматически, когда данный пользователь предпринимает слишком много неудачных попыток входа. Чтобы разблокировать пользователя, понадобится вызвать отдельно метод MembershipUser.UnlockUser().

То же правило действует в отношении пароля. Напрямую изменить пароль, устанавливая свойство MembershipUser, нельзя. Более того, класс MembershipUser вообще не имеет свойства для прямого доступа к паролю. Для этих целей он поддерживает методы GetPassword() и ChangePassword(), которые требуют передачи им старого и нового паролей. Извлечение пароля методом GetPassword() возможно, но только если пароль не хеширован в хранилище. Таким образом, GetPassword() работает, если поставщик членства сконфигурирован на хранение пароля либо в виде простого текста, либо в зашифрованном, но не хешированном виде.

Создание и удаление пользователей

Создание пользователей столь же просто, как и применение остальных средств Membership API. Создавать пользователей можно простым вызовом метода CreateUser() класса Membership. Таким образом, чтобы дополнить свой веб-сайт функцией создания пользователей, добавьте новую страницу, содержащую текстовые поля для ввода необходимой информации, затем добавьте кнопку и, наконец, перехватите событие Click этой кнопки:

<h2>Создать пользователя</h2>
<div>
	Имя:
	<asp:TextBox runat="server" ID="UserNameText" /><br />
	Пароль:
	<asp:TextBox runat="server" ID="PasswordText"
	    TextMode="Password" /><br />
	Повторите пароль:
	<asp:TextBox runat="server" ID="PasswordConfirmText"
	    TextMode="Password" /><br />
	<asp:CompareValidator runat="server" ID="ComparePasswords"
	    ControlToValidate="PasswordText"
	    ControlToCompare="PasswordConfirmtext"
	    ErrorMessage="Пароли должны совпадать" /><br />
	Email:
	<asp:TextBox runat="server" ID="UserEmailText" /><br />
	Секретный вопрос:
	<asp:TextBox runat="server" ID="PwdQuestionText" /><br />
	Ответ:
	<asp:TextBox runat="server" ID="PwdAnswerText" /><br />
	<asp:Button runat="server" ID="ActionAddUser" Text="Создать пользователя..."
	    OnClick="ActionAddUser_Click" /><br />
	<asp:Label runat="server" ID="StatusLabel" Text="" EnableViewState="false" />
</div>
protected void ActionAddUser_Click(object sender, EventArgs e)
{
	try
	{
	    MembershipCreateStatus Status;

	    Membership.CreateUser(UserNameText.Text,
				  PasswordText.Text,
				  UserEmailText.Text,
				  PwdQuestionText.Text,
				  PwdAnswerText.Text, true,
				  out Status);

	    StatusLabel.Text = "Новый юзер успешно создан!";
	}
	catch (Exception ex)
	{
	    System.Diagnostics.Debug.WriteLine("Exception: " + ex.Message);
	    StatusLabel.Text = "Возникла ошибка при создании пользователя!";
	}
}

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

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

Удаление пользователей проще, чем их создание. Класс Membership предлагает метод DeleteUser(), который требует передачи ему в виде параметра только имени пользователя. Он удаляет пользователя и, при желании, всю связанную с ним информацию из хранилища членства.

Проверка пользователей

Последний по порядку, но не по значимости, метод класса Membership предназначен для проверки членства пользователя. Если пользователь вводит имя и пароль в форме регистрации, с помощью метода ValidateUser() можно программно проверить введенную пользователем информацию:

if (Membership.ValidateUser(UsernameText.Text, PasswordText.Text))
{
	FormsAuthentication.RedirectFromLoginPage(UsernameText.Text, false);
}
else
{
	// Неверное имя или пароль
}
Пройди тесты
Лучший чат для C# программистов