Опубликован: 13.07.2010 | Уровень: специалист | Доступ: платный
Самостоятельная работа 37:

Безопасность: аутентификация с помощью форм

< Самостоятельная работа 36 || Самостоятельная работа 37: 12345678

Программное добавление пользователей в конфигурационный файл

  • Добавьте к проекту командой Website/Add New Item страницу без отделенного кода с именем LoginAddUsers.aspx по следующему шаблону

  • Заполните страницу LoginAddUsers.aspx следующим кодом
<%@ Page Language="C#" %>
<%@ Import Namespace="System.Web.Configuration" %>
    
<script runat="server">
    
    protected void btnAddUsers_Click(object sender, EventArgs e)
    {
        // Учетные записи для новых аутентифицированных пользователей
        string[,] authUsers = {
                                {"user1", "password1"},
                                {"user2", "password2"},
                                {"user3", "password3"}
                              };
        
        // Загрузить содержимое корневого Web.config
        Configuration myConfig = System.Web.Configuration.
            WebConfigurationManager.OpenWebConfiguration("~/");
        
        // Найти содержимое секции system.web
        ConfigurationSectionGroup systemWeb = myConfig.SectionGroups["system.web"];
        
        // Найти содержимое секции authentication 
        System.Web.Configuration.AuthenticationSection authSec =
            (System.Web.Configuration.AuthenticationSection)
            systemWeb.Sections["authentication"];
        
        // Установить параметр passwordFormat (Clear, MD5, SHA1) 
        authSec.Forms.Credentials.PasswordFormat = System.Web.Configuration.FormsAuthPasswordFormat.Clear;
        
        // Добавить новых пользователей
        for (int i = 0; i < authUsers.Length / 2; i++)
            authSec.Forms.Credentials.Users.Add(new System.Web.Configuration.FormsAuthenticationUser(
                authUsers[i, 0], authUsers[i, 1]));
        
        // Обновить файл Web.config 
        myConfig.Save();
    
        // Отсылаем сообщение 
        lblUsersResult.Text = "Новые пользователи добавлены!!!";
    }
</script>
    
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Untitled Page</title>
</head>
<body>
    <form id="form1" runat="server">
    <div style="text-align: center">
    <h1>Административная страница добавления учетных записей в Web.config</h1>
        <p>
            <asp:Button ID="btnAddUsers" runat="server" Text="Добавить" OnClick="btnAddUsers_Click" /></p>
        <p>
            <asp:Label ID="lblUsersResult" runat="server"></asp:Label></p>
    </div>
    </form>
</body>
</html>
Листинг 37.4. Страница LoginAddUsers.aspx

Обратите внимание! Чтобы не использовать полные имена классов вместе с их пространствами имен:

В страницах с отделенным кодом используется инструкция using

В страницах с совмещенным кодом используется директива

<%@ Import Namespace="System.Web.Configuration" %>

  • В режиме редактирования страницы LoginAddUsers.aspx выполните команду File/View in Browser
  • Откройте файл Web.config и убедитесь, что страница LoginAddUsers.aspx при выполнении программно добавила новых пользователей, а также скорректировала имена старых пользователей путем приведения символов к нижнему регистру. Но это несущественно, поскольку ASP.NET при сравнении имен регистр символов не учитывает
<credentials passwordFormat="Clear">
     <user name="admin" password="Root" />
     <user name="петя" password="Уф&amp;Уф" />
     <user name="вася" password="!$-*?&quot;" />
     <user name="user1" password="password1" />
     <user name="user2" password="password2" />
     <user name="user3" password="password3" />
    </credentials>
Листинг 37.5. Секция <credentials> файла Web.config после выполнения страницы
  • Добавьте к проекту две страницы без отделенного кода с именами Default.aspx и MyDefault.aspx со следующим кодом
<%@ Page Language="C#" %>
    
<script runat="server">
    
    protected void SignOutAction_Click(object sender, EventArgs e)
    {
        // Уничтожить cookie-набор 
        FormsAuthentication.SignOut();
        // Направить на страницу регистрации
        //FormsAuthentication.RedirectToLoginPage();
    }
</script>
    
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Untitled Page</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <h1>
            Страница с ограниченным доступом Default.aspx</h1>
        <p>
            <asp:Button ID="SignOutAction" runat="server" 
            Text="Отменить регистрацию" OnClick="SignOutAction_Click" />
            <asp:HyperLink ID="HyperLink1" runat="server" 
            NavigateUrl="~/MyDefault.aspx">На страницу MyDefault.aspx...
            </asp:HyperLink></p>
    </div>
    </form>
</body>
</html>
Листинг 37.6. Страница Default.aspx
<%@ Page Language="C#" %>
    
<script runat="server">
    
    protected void SignOutAction_Click(object sender, EventArgs e)
    {
        // Уничтожить cookie-набор 
        FormsAuthentication.SignOut();
        // Направить на страницу регистрации
        //FormsAuthentication.RedirectToLoginPage();
    }
</script>
    
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
    <title>Untitled Page</title>
</head>
<body>
    <form id="form1" runat="server">
        <div>
            <h1>
                Страница с ограниченным доступом MyDefault.aspx</h1>
            <p>
                <asp:Button ID="SignOutAction" runat="server" 
                OnClick="SignOutAction_Click" Text="Отменить регистрацию" />
                <asp:HyperLink ID="HyperLink1" runat="server" 
                NavigateUrl="~/Default.aspx">На страницу Default.aspx...
                </asp:HyperLink></p>
        </div>
    </form>
</body>
</html>
Листинг 37.7. Страница MyDefault.aspx
  • В проводнике решений вызовите контекстное меню для страницы Default.aspx или MyDefault.aspx и выполните команду View in Browser. Убедитесь, что пока ASP.NET разрешает пользоваться этими страницами без регистрации, т.е. любым анонимным пользователям
  • Добавьте в конфигурационный файл блок авторизации, запрещающий доступ всем анонимным пользователям и требующий обязательной регистрации

Окончательный вид файла Web.config должен стать таким

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <system.web>
        <compilation debug="true" />
        <authentication mode="Forms">
            <forms 
                name="MyCookieName" 
                loginUrl="MyLogin.aspx" 
                defaultUrl="MyDefault.aspx"
                protection="All" 
                timeout="20" 
                path="/" 
                requireSSL="false"
                slidingExpiration="true" 
                cookieless="AutoDetect" 
                domain=""
                enableCrossAppRedirects="false">
                <credentials passwordFormat="Clear">
                    <user name="admin" password="Root" />
                    <user name="петя" password="Уф&amp;Уф" />
                    <user name="вася" password="!$-*?&quot;" />
                    <user name="user1" password="password1" />
                    <user name="user2" password="password2" />
                    <user name="user3" password="password3" />
                </credentials>
            </forms>
        </authentication>
        <authorization>
            <deny users="?"/>
        </authorization>
    </system.web>
</configuration>
Листинг 37.8. Добавление требования регистрации в файл Web.config
  • В проводнике решений вновь вызовите контекстное меню для страницы Default.aspx или MyDefault.aspx и выполните команду View in Browser. Убедитесь, что ASP.NET теперь не разрешает пользоваться этими страницами анонимно и пытается адресоваться к странице регистрации, назначенной нами в конфигурационном файле параметром loginUrl="MyLogin.aspx"

Создание страницы регистрации

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

Страница регистрации должна включать в себя поля ввода для получения от пользователя данных удостоверения. Для проверки достоверности пользовательских данных необходимо использовать валидаторы, генерирующие нужный JavaScript -код на клиенте, а также выполняющие проверку на сервере.

  • Создайте заготовку новой страницы с именем MyLogin.aspx без отделенного кода
  • Заполните страницу элементами управления и настройте их согласно таблице
Таблица свойств элементов страницы регистрации MyLogin.aspx
Элемент Свойство Значение Пояснение
Panel ID MainPanel Родительская панель для оформления рамкой
  BorderColor Silver Цвет рамки
  BorderStyle Ridge Тип рамки
TextBox ID UsernameText Текстовое поле ввода имени пользователя
RequiredFieldValidator ID UsernameRequiredValidator Проверка достоверности, чтобы привязанное поле не было пустым
  ControlToValidate UsernameText Привязка к контролируемому элементу ввода
  Display Dynamic Место под элемент выделять только при визуализации
  ErrorMessage Не заполнено поле "Имя пользователя" Отображать в элементе ValidationSummary при ошибке
  ToolTip Пустое поле ввода Всплывающая подсказка для визуализированного валидатора
  Text * Надпись на визуализированном валидаторе
RegularExpressionValidator ID UsernameValidator Валидатор регулярных выражений. Следит за вводом только допустимых символов
  ControlToValidate UsernameText Привязка к контролируемому элементу ввода
  Display Dynamic Место под элемент выделять только при визуализации
  ErrorMessage Неверное имя пользователя Отображать в элементе ValidationSummary при ошибке
  ToolTip Допустимы буквы, цифры, пробелы и подчеркивания Всплывающая подсказка для визуализированного валидатора
  ValidationExpression [а-яА-Я\w| ]*

Регулярное выражение:

  • [] - диапазон пропускаемых символов
  • []* - символы диапазона могут встречаться в контролируемом вводе сколько угодно раз
  • а-яА-Я - разрешать все буквы русского алфавита
  • \w - разрешать все латинские буквы, цифры и знаки подчеркивания. Это управляющий символ регулярного выражения
  • | - знак ИЛИ, после которого стоит пробел, означает, что разрешать и пробелы

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

  Text * Надпись на визуализированном валидаторе
TextBox ID PasswordText Текстовое поле ввода пароля
  TextMode Password Ввод отображается звездочками
RequiredFieldValidator ID PwdRequiredValidator Проверка достоверности, чтобы привязанное поле не было пустым
  ControlToValidate PasswordText Привязка к контролируемому элементу ввода
  Display Dynamic Место под элемент выделять только при визуализации
  ErrorMessage Не заполнено поле "Пароль" Отображать в элементе ValidationSummary при ошибке
  ToolTip Пустое поле ввода Всплывающая подсказка для визуализированного валидатора
  Text * Надпись на визуализированном валидаторе
RegularExpressionValidator ID PwdValidator Валидатор регулярных выражений. Следит за вводом только допустимых символов
  ControlToValidate PasswordText Привязка к контролируемому элементу ввода
  Display Dynamic Место под элемент выделять только при визуализации
  ErrorMessage Неверный пароль Отображать в элементе ValidationSummary при ошибке
  ToolTip Используются недопустимые символы Всплывающая подсказка для визуализированного валидатора
  ValidationExpression [а-яА-Я\w| !"$&amp;/()=\-?\*]* Регулярное выражение:
  • [] - диапазон пропускаемых символов
  • []* - символы диапазона могут встречаться в контролируемом вводе сколько угодно раз
  • а-яА-Я - разрешать все буквы русского алфавита
  • \w - разрешать все латинские буквы, цифры и знаки подчеркивания. Это управляющий символ регулярного выражения
  • | - знак ИЛИ, после которого стоит пробел и ряд других символов, разрешенных для ввода

Символы, которые могут интерпретироваться как служебные, экранируются обратной косой чертой. Интерпретируемый HTML-символ амперсанта заменяется неинтерпретируемым аналогом &amp;

  Text * Надпись на визуализированном валидаторе
Button ID Button1 Кнопка Submit
  Text Отправить Надпись
Label ID lblResult Метка сообщения для заполнения в коде
ValidationSummary ID ValidationSummary1 Элемент отображения сообщений об ошибках, обнаруженных валидаторами

Интерфейсная часть страницы MyLogin.aspx в режиме проектирования будет такой


Код страницы MyLogin.aspx будет таким

<%@ Page Language="C#" EnableViewState="false" %>
    
<script runat="server">
    
    protected void LoginAction_Click(object sender, EventArgs e)
    {
        this.Validate();// Исполнить валидаторы на сервере
        if (!this.IsValid)// Оценить флаг достоверности
            return;// Отправить назад как есть
        
        // Извлечь из web.config и сравнить с введенным 
        if (FormsAuthentication.Authenticate(UsernameText.Text, PasswordText.Text))
        {
            // Создать временный cookie-набор (второй параметр false),
            // записать в него  метку аутентификации и перенаправить
            // на исходную запрошенную страницу или MyDefault.aspx
            FormsAuthentication.RedirectFromLoginPage(UsernameText.Text, false);
        }
        else
        {
            HtmlGenericControl message = new HtmlGenericControl();
            message.InnerHtml = "<h2 style='color: Red'>Неверное имя или пароль!</h2>";
            form1.Controls.Add(message);
        }
    }
</script>
    
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
    <title>Untitled Page</title>
</head>
<body>
    <form id="form1" runat="server">
        <div style="text-align: center">
            <h1>Сегодня <% this.Response.Write(DateTime.Now.ToShortDateString()); %> г.</h1>
            <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>
                            &nbsp;&nbsp;&nbsp;
                        </td>
                        <td align="right" height="43" style="width: 167px">
                            Имя&nbsp;пользователя:</td>
                        <td>
                            &nbsp;<asp:TextBox ID="UsernameText" runat="server" />
                        </td>
                        <td>
                            <asp:RequiredFieldValidator ID="UsernameRequiredValidator" 
                                runat="server" ControlToValidate="UsernameText"
                                Display="Dynamic" 
                                ErrorMessage='Не заполнено поле "Имя пользователя"' 
                                ToolTip="Пустое поле ввода">*
                            </asp:RequiredFieldValidator>
                            <asp:RegularExpressionValidator ID="UsernameValidator" 
                                runat="server" ControlToValidate="UsernameText"
                                Display="Dynamic" ErrorMessage="Неверное имя пользователя" 
                                ToolTip="Допустимы буквы, цифры, пробелы и подчеркивания"
                                ValidationExpression="[а-яА-Я\w| ]*">*
                            </asp:RegularExpressionValidator>
                        </td>
                    </tr>
                    <tr>
                        <td>
                            &nbsp;&nbsp;&nbsp;
                        </td>
                        <td align="right" height="43" style="width: 167px">
                            &nbsp;Пароль:</td>
                        <td>
                            &nbsp;<asp:TextBox ID="PasswordText" runat="server" 
                                TextMode="Password" />
                        </td>
                        <td>
                            <asp:RequiredFieldValidator ID="PwdRequiredValidator" 
                                runat="server" ControlToValidate="PasswordText"
                                Display="Dynamic" ErrorMessage='Не заполнено поле "Пароль"' 
                                ToolTip="Пустое поле ввода">*
                            </asp:RequiredFieldValidator>
                            <asp:RegularExpressionValidator ID="PwdValidator" runat="server" 
                                ControlToValidate="PasswordText"
                                Display="Dynamic" ErrorMessage="Неверный пароль" 
                                ToolTip="Используются недопустимые символы"
                                ValidationExpression='[а-яА-Я\w| !"$&amp;/()=\-?\*]*'>*
                            </asp:RegularExpressionValidator>
                        </td>
                    </tr>
                </table>
                <asp:Button ID="Button1" runat="server" Text="Отправить" 
                    OnClick="LoginAction_Click" />
            </asp:Panel>
            <asp:Label ID="lblResult" runat="server" />
        </div>
        <asp:ValidationSummary ID="ValidationSummary1" runat="server" />
    </form>
</body>
</html>
Листинг 37.9. Код страницы регистрации MyLogin.aspx
  • В проводнике решений вызовите контекстное меню для страницы Default.aspx или MyDefault.aspx и выполните команду View in Browser

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

< Самостоятельная работа 36 || Самостоятельная работа 37: 12345678
Иван Циферблат
Иван Циферблат
Россия, Таганрог, 36, 2000