Безопасность: аутентификация с помощью форм
Упражнение 5. Административная страница создания пользователей в БД
Для создания и удаления пользователей следует применить перегруженные статические методы CreateUser() и DeleteUser() класса Membership. Нужно создать административные страницы, содержащие требуемые поля для ввода информации. Поля можно контролировать валидаторами, хотя это и необязательно, поскольку эти страницы административные, пользоваться такими страницами будут администраторы, которые будут строго соблюдать правила ввода.
Метод CreateUser() имеет несколько перегрузок, из которых простейшая принимает только имя и пароль. В то же время более полные перегрузки требуют ввода контрольного вопроса и ответа на него. В самой полной перегрузке метод CreateUser() содержит экземпляр перечисления MembershipCreateStatus в качестве выходного параметра, позволяющий проанализировать причину ошибки в случае ее возникновения. По умолчанию требуется применять наиболее полную перегрузку метода CreateUser(), включающую контрольный вопрос и ответ, чтобы избежать выброса исключения MembershipCreateUserException.
Удаление пользователя выполняется методом Membership.DeleteUser(string), которому передается в качестве параметра уникальное имя пользователя. Пользователь безвозвратно удаляется из всех таблиц вместе со всей связанной с ним информацией.
В качестве примера создадим собственную страницу добавления, имеющую аналогичную функциональность с WAT, и отдельно страницу удаления пользователя в БД. Для простоты эти страницы мы переделаем из страницы регистрации MyLogin.aspx.
-
Скопируйте
страницу MyLogin.aspx и присвойте копии
имя AddUserMembership.aspx
Провайдер базы данных не добавляет новых пользователей, если пароль имеет длину менее 7 символов и если среди них нет хотя-бы одного неалфавитно-цифрового символа. Для проверки выполнения этого условия, а также для тренировки, закрепим за полем пароля кодируемый элемент проверки достоверности CustomValidator. С помощью этого элемента реализуем проверку достоверности на клиенте и на сервере.
Неалфавитно-цифровые символы представим в виде ASCII -кодов согласно следующей таблице
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | |
|---|---|---|---|---|---|---|---|---|---|---|
| 0 | ||||||||||
| 1 | ||||||||||
| 2 | ||||||||||
| 3 | ! | " | # | $ | % | & | ' | |||
| 4 | ( | ) | * | + | , | . | / | |||
| 5 | : | ; | ||||||||
| 6 | < | = | > | ? | @ | |||||
| 7 | ||||||||||
| 8 | ||||||||||
| 9 | [ | \ | ] | ^ | _ | |||||
| 10 | ||||||||||
| 11 | ||||||||||
| 12 | { | | | } | ~ |
Строка ASCII -кодов неалфавитно-цифровых символов на JavaScript будет такой:
var nonAlphanumericCharactersString = String.fromCharCode(33,34,35,36,37,38,39,40,41,42,43,44,45,46, 58,59,60,61,62,63,64,91,92,93,94,95,123,124,125,126);
-
Переделайте
интерфейсную и скриптовую части страницы, чтобы она стала
такой
<%@ Page Language="C#" EnableViewState="false" %>
<script runat="server">
// Блок на C# по умолчанию
protected void Page_Load(object sender, EventArgs e)
{
// Вынесли из интерфейсной части из-за большой ширины листинга
passwordValidator.ErrorMessage =
"Пароль должен иметь длину не менее 7 символов"
+ " и содержать хотя бы один неалфавитно-цифровой символ";
}
protected void AddUserMembership_Click(object sender, EventArgs e)
{
this.Validate();// Исполнить валидаторы на сервере
if (!this.IsValid)// Оценить флаг достоверности
return;// Отправить назад как есть
// Создаем экземпляр перечисления
MembershipCreateStatus status;
// Попытка добавить
try
{
Membership.CreateUser(
username.Text,
password.Text,
email.Text,
question.Text,
answer.Text,
true,
out status
);
lblResult.Text = String.Empty;
switch (status)
{
case MembershipCreateStatus.DuplicateUserName:
lblResult.Text = "Дублированное имя пользователя<br/>";
goto default;
case MembershipCreateStatus.ProviderError:
lblResult.Text = "Ошибка Поставщика<br/>";
goto default;
default: // Дальше лень анализировать
lblResult.Text += "Пользователь не создан";
lblResult.ForeColor = System.Drawing.Color.Red;
break;
case MembershipCreateStatus.Success:
// Выдаем успешную информацию
lblResult.Text = "Пользователь " + username.Text
+ " создан успешно!";
// Рекурсивно очищаем все текстовые поля ввода
EmptyTextBox(form1.Controls);
lblResult.Text += "<br/>Поля ввода очищены";
break;
}
}
// Откат
catch (MembershipCreateUserException ex)
{
lblResult.Text = "<h2 style='color: Red'>Ошибка создания пользователя</h2>";
System.Diagnostics.Debug.WriteLine("Exception: "
+ ex.Message);
}
}
private void EmptyTextBox(ControlCollection controls)
{
foreach (Control ctrl in controls)
{
if (ctrl is TextBox)
((TextBox)ctrl).Text = String.Empty;
// Идем в глубину иерархической цепочки и ищем дочерние элементы
if (ctrl.Controls != null)
EmptyTextBox(ctrl.Controls);
}
}
</script>
<script language="C#" runat="server">
// Еще один блок с явным указанием C#, хотя можно атрибут языка и не указывать
// Проверка допустимости пароля на сервере
// Обработчик события ServerValidate элемента CustomValidator
protected void passwordValidator_ServerValidate(object source, ServerValidateEventArgs args)
{
string data = args.Value;
// Установить начальное значение флага достоверности
args.IsValid = false;
// Проверить длину пароля
if (data.Length < 7)
return;
// Проверить наличие неалфавитноцифрового символа
// Формируем массив неалфавитноцифровых символов по их кодам,
// чтобы не связываться с интерпретируемыми символами
int[] nonAlphanumericCharactersCode =
{33,34,35,36,37,38,39,40,41,42,43,44,45,46,
58,59,60,61,62,63,64,91,92,93,94,95,123,124,125,126};
// Перебираем символы пользовательского ввода
foreach (char ch in data)
{
for (int i = 0; i < nonAlphanumericCharactersCode.Length; i++)
if (ch == Convert.ToChar(nonAlphanumericCharactersCode[i]))
{
// Пароль допустим
args.IsValid = true;
return;
}
}
}
</script>
<script language="javascript" type="text/javascript">
// Проверка допустимости пароля на клиенте. Работает при включенном
// по умолчанию свойстве EnableClientScript элемента CustomValidator
function ValidatePassword(source, args)
{
// Расщепить строку на массив символов с пустым разделителем
var data = args.Value.split("");
// Установить начальное значение флага достоверности
args.IsValid = false;
// Проверить длину пароля
if(data.length < 7)
return;
// Проверить наличие неалфавитноцифрового символа
// Формируем строку неалфавитноцифровых символов по их кодам,
// чтобы не связываться с интерпретируемыми символами
var nonAlphanumericCharactersString =
String.fromCharCode(33,34,35,36,37,38,39,40,41,42,43,44,45,46,
58,59,60,61,62,63,64,91,92,93,94,95,123,124,125,126);
for(var ch in data)
{
if(nonAlphanumericCharactersString.indexOf(data[ch]) != -1)
{
// Пароль допустим
args.IsValid = true;
return;
}
}
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
<title>Добавление пользователей в БД</title>
</head>
<body>
<form id="form1" runat="server">
<div style="text-align: center">
<h2 id="H2_1" runat="server">
Введите учетную запись для добавления пользователя</h2>
<asp:Panel ID="MainPanel" runat="server" BorderColor="Silver" BorderStyle="Ridge"
BorderWidth="2px" Height="90px" Width="364px">
<table cellpadding="5" style="width: 137%">
<tr>
<td>
</td>
<td align="right" height="43" style="width: 224px">
Имя пользователя:
</td>
<td>
<asp:TextBox ID="username" runat="server" />
</td>
<td>
<asp:RequiredFieldValidator ID="usernameRequiredValidator"
runat="server" ControlToValidate="username"
ErrorMessage='Не заполнено поле "Имя пользователя"'
Display="Dynamic">*</asp:RequiredFieldValidator>
</td>
</tr>
<tr>
<td>
</td>
<td align="right" height="43" style="width: 224px">
Пароль:
</td>
<td>
<asp:TextBox ID="password" runat="server" />
</td>
<td>
<asp:RequiredFieldValidator ID="passwordRequiredValidator"
runat="server" ControlToValidate="password"
ErrorMessage='Не заполнено поле "Пароль"'
Display="Dynamic">*</asp:RequiredFieldValidator>
<asp:CustomValidator ID="passwordValidator" runat="server"
ControlToValidate="password"
Display="Dynamic"
ClientValidationFunction="ValidatePassword"
OnServerValidate="passwordValidator_ServerValidate">*</asp:CustomValidator>
</td>
</tr>
<tr>
<td>
</td>
<td align="right" height="43" style="width: 224px">
E-mail:</td>
<td>
<asp:TextBox ID="email" runat="server"></asp:TextBox>
</td>
<td>
<asp:RequiredFieldValidator ID="emailRequiredValidator"
runat="server" ControlToValidate="email"
ErrorMessage='Не заполнено поле "E-mail"'
Display="Dynamic">*</asp:RequiredFieldValidator>
<asp:RegularExpressionValidator ID="emailValidator" runat="server"
ControlToValidate="email" ErrorMessage="Неверный E-mail"
ValidationExpression="\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*"
Display="Dynamic">*</asp:RegularExpressionValidator>
</td>
</tr>
<tr>
<td>
</td>
<td align="right" height="43" style="width: 224px">
Контрольный вопрос:</td>
<td>
<asp:TextBox ID="question" runat="server"></asp:TextBox>
</td>
<td>
<asp:RequiredFieldValidator ID="questionRequiredValidator"
runat="server" ControlToValidate="question"
ErrorMessage='Не заполнено поле "Контрольный вопрос"'
Display="Dynamic">*</asp:RequiredFieldValidator>
</td>
</tr>
<tr>
<td>
</td>
<td align="right" height="43" style="width: 224px">
Контрольный ответ:</td>
<td>
<asp:TextBox ID="answer" runat="server"></asp:TextBox>
</td>
<td>
<asp:RequiredFieldValidator ID="answerRequiredValidator"
runat="server" ControlToValidate="answer"
ErrorMessage='Не заполнено поле "Контрольный ответ"'
Display="Dynamic">*</asp:RequiredFieldValidator>
</td>
</tr>
<tr>
<td colspan="4" align="center">
<asp:Button ID="btnAddUser" runat="server"
Text="Добавить" OnClick="AddUserMembership_Click" />
</td>
</tr>
</table>
</asp:Panel>
<asp:Label ID="lblResult" runat="server" Font-Bold="True"
Font-Size="Large" ForeColor="Blue" />
</div>
<asp:ValidationSummary ID="ValidationSummary1" runat="server" />
</form>
</body>
</html>
Листинг
37.16.
Административная страница AddUserMembership.aspx добавления пользователей в БД
-
Выполните
страницу AddUserMembership.aspx и убедитесь
в работоспособности рассматриваемого механизма добавления
пользователей в БД SQL Server
Упражнение 6. Административная страница удаления пользователей из БД
Теперь рассмотрим вопрос удаления пользователей. Он намного проще, чем создание. Нужно только применить метод System.Web.Security.Membership.DeleteUser(), который имеет две перегрузки:
- public static bool DeleteUser( string username ) - удаляет по имени пользователя все связанные с ним данные из всех таблиц БД
- public static bool DeleteUser( string username, bool deleteAllRelatedData ) - удаляет пользователя только из таблицы aspnet_Users, если флаг равен false. Иначе удаляет все связанные с пользователем данные при флаге равном true
Обе перегрузки возвращают true, если пользователь успешно удален, иначе false.
-
Разработайте
из копии страницы MyLogin.aspx административную
страницу удаления пользователей DeleteUserMembership.aspx, которая будет примерно
такой
<%@ Page Language="C#" EnableViewState="false" %>
<script runat="server">
protected void DeleteUser_Click(object sender, EventArgs e)
{
if (Membership.DeleteUser(username.Text))
{
lblResult.Text="Пользователь " + username.Text
+ " успешно удален";
username.Text = "";
}
else
{
lblResult.Text = "Пользователь не удален";
lblResult.ForeColor = System.Drawing.Color.Red;
}
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
<title>Удаление пользователей из БД</title>
</head>
<body>
<form id="form1" runat="server">
<div style="text-align: center">
<h2>
Введите имя удаляемого пользователя</h2>
<asp:Panel ID="MainPanel" runat="server" BorderColor="Silver"
BorderStyle="Ridge"
BorderWidth="2px" Height="90px" Width="412px">
<table cellpadding="5" style="width: 100%">
<tr>
<td align="right" height="43" style="width: 167px">
Имя пользователя:</td>
<td>
<asp:TextBox ID="username" runat="server" />
</td>
</tr>
</table>
<asp:Button ID="Button1" runat="server" Text="Удалить"
OnClick="DeleteUser_Click" /></asp:Panel>
<asp:Label ID="lblResult" runat="server" Font-Bold="True"
Font-Size="Large" ForeColor="Blue">
</asp:Label>
</div>
</form>
</body>
</html>
Листинг
37.16.
Админ. страница DeleteUserMembership.aspx удаления пользователей из БД
-
Испытайте
страницу удаления пользователей