Опубликован: 11.09.2006 | Доступ: свободный | Студентов: 7433 / 307 | Оценка: 4.26 / 3.45 | Длительность: 30:46:00
ISBN: 978-5-9556-0080-2
Лекция 10:

Безопасность Windows-форм

Контроль доступа приложения

После создания объекта роли к нему можно добавить код для реализации контроля доступа, основанного на ролях пользователей. Рассмотрим пример, в котором осуществляется контроль доступа по имени пользователя, причем сравнение строк не чувствительно к регистру. Создайте новое консольное приложение и назовите его AccessControl. Далее привожу листинг с комментариями:

using System;
using System.Threading;
using System.Security.Principal;

namespace AccessControl
{
        class Class1
        {
                [STAThread]
                static void Main(string[] args)
                {
                        GenericIdentity identity = new GenericIdentity("MANAGER");
                        string[] userRoles = new string[]{"Administrator"};
                        GenericPrincipal principal = new GenericPrincipal(identity, userRoles);
                        Thread.CurrentPrincipal = principal;

                        ValidateUserName();
                        ValidateRole();
                }
                //Проверяем пользователя по личности
                static void ValidateUserName()
                {
                        if (String.Compare(Thread.CurrentPrincipal.Identity.Name, "manager", true) == 0)
                        {
                                Console.WriteLine("Добро пожаловать, пользователь Manager");
                        }
                        else
                        {
                                throw new System.Security.SecurityException("У вас нет прав для выполнения текущей операции");
                        }
                }
                //Проверяем пользователя по роли
                static void ValidateRole()
                {
                        if (Thread.CurrentPrincipal.IsInRole("Administrator"))
                        {
                        Console.WriteLine("Добро пожаловать, пользователь Manager");
                        }
                        else
                        {
                                throw new System.Security.SecurityException("У вас нет прав для выполнения текущей операции");
                        }
                }
        }
}
Листинг 10.4.

При запуске этого приложения дважды осуществляется авторизацияпо имени пользователя (личности) и его роли (рис. 10.14):

Результат работы приложения AccessControl

Рис. 10.14. Результат работы приложения AccessControl

Для объектов класса WindowsIdentity имя пользователя представлено в виде имени пользователя и домена. Например, если бы приведенный выше пример использовал объект класса WindowsIdentity, то имя для сравнения было бы следующим: DOMAIN\Manager.

Для объектов класса WindowsPrincipal роль включает в себя и имя домена. Ниже представлен пример проверки роль объектом класса WindowsPrincipal:

if(WindowsPrincipalObj.IsInRole("DOMAIN\\ Manager "))
// Разрешить действие

Если учесть, что ваше приложение может кочевать по сети в поисках нового пользователя, то строго прописывать имя домена не рекомендуется. Вместо этого для проверки ролей пользователей объектом класса WindowsPrincipal нужно указывать не строку с названием роли, а член перечисления WindowsBuiltInRole, как показано ниже:

MyPrincipal.IsInRole(WindowsBuiltInRole. Manager);

На диске, прилагаемом к книге, вы найдете приложение AccessControl (Code\Glava10\ AccessControl).

Приложение CustomSecurity — использование собственной технологии ролевой безопасности

Мы обсудили теоретические основы безопасности .NET Framework, займемся теперь практическим использованием этих концепций. Создайте новое Windows-приложение и назовите его CustomSecurity. При запуске приложение будет требовать авторизацию пользователя и, в зависимости от его роли, предоставлять разные права доступа. В главной форме будет отображаться список всех пользователей и предоставляться возможность изменять роль пользователей. Список пользователей будет содержаться в файле Users.xml, для его создания в окне щелкаем правой кнопкой мыши в окне Solution Explorer и выбираем Add/Add New Item… . В появившемся окне выбираем XML File. Создадим нескольких пользователей, относящихся к трем группам — admin, manager, operator:

<?xml version="1.0" encoding="utf-8" ?>
<users>
        <user name="admin" id="1" role="admin" />
        <user name="manager" id="2" role="manager" />
        <user name="accountant" id="3" role="accountant" />
        <user name="student1" id="4" role="operator" />
        <user name="student2" id="5" role="operator" />
        <user name="student3" id="6" role="operator" />
</users>

Для просмотра и редактирования данных в виде таблицы щелкните на кнопкеryjgrf, расположенной внизу на панели. Закончив редактирование, скопируйте файл Users.xml из папки проекта в папку bin/Debug.

Вынесем логику определения личности и роли пользователей в отдельные классы — CustomIdentity.cs и CustomPrincipal.cs. Для добавления в проект отдельных классов щелкаем в окне Solution Explorer правой кнопкой и выбираем Add/ Add Class… . Далее привожу листинг CustomIdentity.cs c комментариями:

using System;
using System.Security.Principal;
using System.Xml;

namespace CustomSecurity
{
        /// <summary>
        /// Класс CustomIdentity , описывающий "личность", наследует от класса IIdentity
        /// </summary>
        public class CustomIdentity : IIdentity
        {
                //Вводим переменные  аутентификации
                private bool _isAuth;
                private string _name;
                private string _authType;
                private int _id;
                /// <summary>
                /// Конструктор.
                /// </summary>
                public CustomIdentity()
                {
                        this._isAuth = false;
                        this._authType = String.Empty;
                        this._name = String.Empty;
                        this._id = -1;
                }
                /// <summary>
                ///Создаем конструктор, принимающий имя пользователя.
                /// </summary>
                /// <param name="userName">Имя пользователя.</param>
                public CustomIdentity(string userName)
                {
                        this._id = this.AuthUserName(userName);
                        this._name = userName;
                        this._isAuth = true;
                        this._authType = "Частный тип аутентификации.";
                }
                /// <summary>
                /// Определяем уникальный идентификатор пользователя.
                /// </summary>
                public int ID
                {
                        get { return this._id; }
                }
                #region IIdentity Members
                /// <summary>
                /// Проверка аутентификации пользователя.
                /// </summary>
                public bool IsAuthenticated
                {
                        get
                        {
                                // Реализуем свойство интерфейса.
                                return this._isAuth;
                        }
                }
                /// <summary>
                /// Определяем имя пользователя.
                /// </summary>
                public string Name
                {
                        get
                        {
                                // Реализуем свойство интерфейса.
                                return this._name;
                        }
                }
                /// <summary>
                /// Определяем тип аутентификации.
                /// </summary>
                public string AuthenticationType
                {
                        get
                        {
                                // Реализуем свойство интерфейса.
                                return this._authType;
                        }
                }

                #endregion
                /// <summary>
                /// Проверяем, существует ли имя пользователя  в  базе данных — файле XML.
                /// </summary>
                /// <param name="name">Имя пользователя.</param>
                /// <returns>ID пользователя.</returns>
                private int AuthUserName(string name)
                {
                        // Считываем и сравниваем имя пользователя.
                        XmlTextReader xmlReader = new XmlTextReader("Users.xml");
                        xmlReader.WhitespaceHandling = WhitespaceHandling.None;
                        while(xmlReader.Read())
                        {
                                if(xmlReader["name"] == name)
                                        return Int32.Parse(xmlReader["id"]);
                        }
                        // Если пользователь не найден, генерируем исключение.
                        throw new System.Security.SecurityException(String.Format("Пользователь {0} не найден в базе  данных.", name));
                }
        }
}
Листинг 10.5.

Листинг CustomPrincipal.cs:

using System;
using System.Security.Principal;
using System.Xml;

namespace CustomSecurity
{
        /// <summary>
        /// Класс CustomPrincipal, описывающий роль, наследует от класса IPrincipal
        /// </summary>
        public class CustomPrincipal :IPrincipal
        {
                private CustomIdentity _indentity;
                private string _role;
                /// <summary>
                /// Конструктор.
                /// </summary>
                /// <param name="identity">Определяем личность пользователя.</param>
                public CustomPrincipal(CustomIdentity identity)
                {
                        // Инициализируем личность
                        this._indentity = identity;
                        // Инициализируем переменную только один раз. Если роль изменится в процессе выполнения приложения, то
                        // изменения вступят в силу только после перезагрузки приложения.
                        this._role = this.GetUserRole();
                }
                #region IPrincipal Members
                /// <summary>
                /// Свойство личности пользователя.
                /// </summary>
                public IIdentity Identity
                {
                        get
                        {
                                // Реализуем свойство интерфейса.
                                return this._indentity;
                        }
                }
                /// <summary>
                /// Проверяем, прнадлежит ли пользователь к заданной роли.
                /// </summary>
                /// <param name="role">Роль.</param>
                /// <returns></returns>
                public bool IsInRole(string role)
                {
                        // Реализуем метод интерфейса.
                        return role == this._role;


                        // Если необходимо реагировать на изменение роли без перезагрузки приложения, то это можно сделать так:
                        //return role == this.GetUserRole();
                }

                #endregion
                /// <summary>
                /// Возвращаем  роль пользователя.
                /// </summary>
                /// <returns></returns>
                private string GetUserRole()
                {
                        // Считываем и сравниваем имя пользователя.
                        XmlTextReader xmlReader = new XmlTextReader("Users.xml");
                        xmlReader.WhitespaceHandling = WhitespaceHandling.None;
                        while(xmlReader.Read())
                        {
                                if(xmlReader["name"] == this._indentity.Name)
                                        return xmlReader["role"];
                        }
                        // Если роль пользователя не найдена, генерируем исключение.
                        throw new System.Security.SecurityException(String.Format("Роль пользователя {0} не найдена в базе данных.",
                                this._indentity.Name));
                }
        }
}
Листинг 10.6.
Елена Дьяконова
Елена Дьяконова

При нажатии на Сумма в примере ArbitraryMethod из Лекция 7, VS 2013 выдается ошибка: 

Необработанное исключение типа "System.InvalidOperationException" в System.Windows.Forms.dll

Дополнительные сведения: Недопустимая операция в нескольких потоках: попытка доступа к элементу управления "lblResult" не из того потока, в котором он был создан.

Затем:

Необработанное исключение типа "System.InvalidOperationException" в mscorlib.dll

Дополнительные сведения: Для каждой асинхронной операции метод EndInvoke может вызываться только один раз.

Александр Сороколет
Александр Сороколет

Свойство WindowState формы blank Maximized. Не открывается почемуто на всё окно, а вот если последующую форму бланк открыть уже на макс открывается :-/