При нажатии на Сумма в примере ArbitraryMethod из Лекция 7, VS 2013 выдается ошибка: Необработанное исключение типа "System.InvalidOperationException" в System.Windows.Forms.dll Дополнительные сведения: Недопустимая операция в нескольких потоках: попытка доступа к элементу управления "lblResult" не из того потока, в котором он был создан. Затем: Необработанное исключение типа "System.InvalidOperationException" в mscorlib.dll Дополнительные сведения: Для каждой асинхронной операции метод EndInvoke может вызываться только один раз. |
Безопасность Windows-форм
Объект "личность"
Объекты "личность" и "роль" применяются для доступа к информации о пользователе. Мы можем использовать информацию об имени встроенной учетной записи в операционной системе Windows и роли этой учетной записи с помощью объектов WindowsIdentity и WindowsPrincipal. Для доступа к информации о пользователе, основанной на собственном механизме аутентификации, задействуются объекты GenericIdentity и GenericPrincipal.
Объект "личность" инкапсулирует такую информацию о пользователе, как имя и тип аутентификации. В библиотеке .NET Framework есть три типа объекта "личность" (таблица 10.6).
Личность | Описание |
---|---|
Windows Identity | Представляет информацию о текущей учетной записи Windows. Windows Identity позволяет определять полномочия пользователя в ОС и использовать их в приложении. Реализуется классом WindowsIdentity |
Generic Identity | Представляет информацию о пользователе, которая основана на частном механизме аутентификации, используемом в приложении. Реализуется классом GenericIdentity |
Custom Identity | Представляет "личность", которая инкапсулирует частную информацию о пользователе. Реализуется классом, в котором имеется интерфейс IIdentity |
Все классы, описывающие "личность", должны реализовывать интерфейс IIdentity. Интерфейс IIdentity имеет три открытых свойства:
- Name — имя пользователя.
- IsAuthenticated — логическая переменная, принимающая одно из двух значений в зависимости от результата прохождения пользователем аутентификации.
- AuthenticationType — тип аутентификации пользователя.
Объект "роль"
"Роль" определяет право пользователей на выполнение действий, причем возможно наличие нескольких пользователей (входящих в группу) с различными именами, но равными ролями. Практически такая ситуация характерна для информационных систем — например, в банке права менеджера и оператора различаются, причем может быть несколько как менеджеров, так и операторов.
В библиотеке .NET Framework есть три типа объекта "роль" (таблица 10.7).
Все классы, описывающие объект "роль", должны реализовывать интерфейс IPrincipal. Интерфейс IPrincipal имеет одно свойство — Identity, которое описывает объект класса, реализующего интерфейс Iidentity, и метод — IsInRole, который определяет, принадлежит ли текущий "принципал" к заданной роли.
Использование объектов WindowsIdentity и WindowsPrincipal
Существует два способа создания объекта WindowsPrincipal. Разница между ними в том, что один способ проверяет введенную информацию один раз, а второй — постоянно.
Если однократной проверки роли достаточно, то создаем объект WindowsPrincipal следующим образом:
// Инициализируем объект класса WindowsIdentity // с помощью статического метода WindowsIdentity.GetCurrent() WindowsIdentity identity = WindowsIdentity.GetCurrent(); // Создаем новый объект класса WindowsPrincipal // и передаем в качестве параметра объект identity WindowsPrincipal principal = new WindowsPrincipal(identity);
Если же вам необходимо проверять роль пользователя постоянно, то лучше создать объект WindowsPrincipal следующим образом:
// Указываем домену приложения политику ролевой безопасности // с помощью члена WindowsPrincipal перечисления PrincipalPolicy, // переданного в статический метод AppDomain.CurrentDomain. // SetPrincipalPolicy. AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal); // После того как новая политика установлена, вы можете использовать // объект из статического свойства CurrentPrincipal класса Thread. WindowsPrincipal principal = System.Threading.Thread.CurrentPrincipal as WindowsPrincipal;
Создайте новое консольное приложение и назовите его WindowsIdentityandPrincipal. Далее привожу листинг с комментариями:
using System; //Подключаем пространства имен Threading и Principal using System.Threading; using System.Security.Principal; namespace WindowsIdentityandPrincipal { class Class1 { [STAThread] static void Main(string[] args) { // Создаем и инициализируем объекты // WindowsPrincipal и WindowsIdentity WindowsIdentity identity = WindowsIdentity.GetCurrent(); WindowsPrincipal principal = new WindowsPrincipal(identity); // Выводим информацию, содержащуюся в объекте класса WindowsPrincipal Output("Name", principal.Identity.Name); Output("Type", principal.Identity.AuthenticationType); Output("Authenticated", principal.Identity.IsAuthenticated.ToString()); // Выводим информацию, содержащуюся в объекте класса WindowsIdentity Output("IdentName", identity.Name); Output("IdentType", identity.AuthenticationType); Output("IdentIsAuthenticated", identity.IsAuthenticated.ToString()); Output("IsAnonymous", identity.IsAnonymous.ToString()); Output("IsGuest", identity.IsGuest.ToString()); Output("IsSystem", identity.IsSystem.ToString()); Output("Token", identity.Token.ToString()); } //Метод Output выводит информацию на экран, причем myName — это название //параметра, а myValue — его значение. public static void Output(string myName, string myValue) { Console.WriteLine(myName + "= {0}", myValue); }Листинг 10.2.
В результате выводится полный список значений WindowsIdentity и WindowsPrincipal на данном компьютере (рис. 10.12).
На диске, прилагаемом к книге, вы найдете приложение WindowsIdentityandPrincipal (Code\Glava10\ WindowsIdentityandPrincipal).
Использование объектов GenericIdentity и GenericPrincipal
Классы GenericPrincipal совместно с классом GenericIdentity применяются для реализации ролевой безопасности, не зависящей от системы безопасности Windows. Например, у пользователя запрашиваются имя и пароль, которые затем сверяются с данными, хранящимися в приложении или локальной базе данных, и, после успешной проверки, создаются объекты GenericPrincipal и GenericIdentity на основании введенных значений.
Для реализации ролевой безопасности на основе объектов классов GenericPrincipal и GenericIdentity необходимо выполнить следующие действия:
- создать новый объект класса GenericIdentity и инициализировать его именем пользователя;
- создать новый объект класса GenericPrincipal и инициализировать его только что созданным объектом класса GenericIdentity и строковым массивом, содержащим роли пользователя;
- прикрепить созданный объект класса GenericPrincipal к текущему потоку. Прикрепление к текущему потоку необходимо для осуществления последующей проверки полномочий пользователя в коде приложения.
Синтаксис этих действий следующий:
// Создаем и инициализируем именем пользователя // объект класса GenericIdentity GenericIdentity identity = new GenericIdentity("Username"); // Создаем строковый массив, содержащий роли пользователя. string[] userRoles = new string[]{"Administrator", "PowerUser", "GuestUser"}; // Создаем объект класса GenericPrincipal и инициализируем его // объектом класса GenericIdentity identity и строковым массивом с // ролями. GenericPrincipal principal = new GenericPrincipal(identity, userRoles); // Прикрепляем объект роли к текущему процессу. // Этот и все дочерние процессы будут иметь данную роль. Thread.CurrentPrincipal = principal;
Создайте новое консольное приложение и назовите его GenericIdentityandPrincipal . Далее привожу листинг с комментариями:
using System; using System.Threading; using System.Security.Principal; namespace GenericIdentityandPrincipal { /// <summary> /// Summary description for Class1. /// </summary> class Class1 { [STAThread] static void Main(string[] args) { // Создаем и прикрепляем объект роли. CreateGenericPrincipalAndIdentity(Roles.PowerUser); // Вводим один из способов осуществления проверки роли. if(Thread.CurrentPrincipal.IsInRole("User")) { Console.WriteLine("У вас нет прав для работы с этим приложением"); } else if(Thread.CurrentPrincipal.IsInRole("PowerUser")) { Console.WriteLine("Добро пожаловать, {0}. Ваша роль — Продвинутый пользователь", Thread.CurrentPrincipal.Identity.Name); } else // Administrator { Console.WriteLine("Добро пожаловать, {0}. Ваша роль — Администратор", Thread.CurrentPrincipal.Identity.Name); } } // Создание объектов личности и роли static void CreateGenericPrincipalAndIdentity(Roles role) { // Создаем и инициализируем именем пользователя // объект класса GenericIdentity GenericIdentity identity = new GenericIdentity("Username"); // Создаем строковый массив, содержащий роли пользователя. string[] userRoles = new string[]{role.ToString()}; // Создаем объект класса GenericPrincipal и инициализируем его // объектом класса GenericIdentity identity и строковым массивом с ролями. GenericPrincipal principal = new GenericPrincipal(identity, userRoles); // Прикрепляем объект роли к текущему процессу. // Этот и все дочерние процессы будут иметь данную роль. Thread.CurrentPrincipal = principal; } enum Roles { Administrator, PowerUser, User } } }Листинг 10.3.
Если пользователь проходит проверку, он получает дальнейший доступ (рис. 10.13).
На диске, прилагаемом к книге, вы найдете приложение GenericIdentityandPrincipal (Code\Glava10\ GenericIdentityandPrincipal).