Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

RUS_-_Karejev_-_Razrabotka_Windows-prilozhenij

.pdf
Скачиваний:
36
Добавлен:
02.02.2015
Размер:
8 Мб
Скачать
☆

//Создаем и инициализируем именем пользователя

//объект класса 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).

Рис. 10.13. Результат приложения GenericIdentityandPrincipal

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

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

После создания объекта роли к нему можно добавить код для реализации контроля доступа, основанного на ролях пользователей. Рассмотрим пример, в котором осуществляется контроль доступа по имени пользователя, причем сравнение строк не чувствительно к регистру. Создайте новое консольное приложение и назовите его 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):

Рис. 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>

Для просмотра и редактирования данных в виде таблицы щелкните на кнопке , расположенной внизу на панели. Закончив редактирование, скопируйте файл 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.

Теперь займемся пользовательским интерфейсом программы и привязкой обработчиков. Все приложения, которые мы рассматривали в предыдущих лекциях, я сопровождал описанием дизайна форм и не указывал в листинге область Windows Form

Designer generated code. Сейчас я поступлю наоборот — я приведу код, генерируемый средой, и изображения формы, а вы,

скопировав код, относящийся к дизайну, разберетесь с элементами, которые были использованы для создания интерфейса. Итак, главная форма программы будет иметь следующий вид (рис. 10.14):

Рис. 10.15. Главная форма проекта CustomSecurity

В окне Solution Explorer переименуйте Form1.cs в MainForm.cs, добавьте на форму элемент управления ImageList и поместите в коллекцию две иконки (на рис. 10.15 эти иконки были использованы для кнопок панели инструментов).

Листинг формы MainForm:

using System;

using System.Drawing; using System.Collections;

using System.ComponentModel; using System.Windows.Forms; using System.Data;

using System.Threading; using System.Xml;

using System.Xml.XPath; using System.IO;

namespace CustomSecurity

{

///<summary>

///Главная форма.

///</summary>

public class MainForm : System.Windows.Forms.Form

{

private System.Windows.Forms.ToolBarButton btnViewUsers; private System.Windows.Forms.ToolBarButton btnEditUsers; private System.Windows.Forms.ImageList toolBoxIcons; private System.Windows.Forms.ToolBar toolBar;

private System.Windows.Forms.ListView lstViewUsers; private System.Windows.Forms.ColumnHeader colUserName; private System.Windows.Forms.ColumnHeader colUserRole; private System.Windows.Forms.ColumnHeader colUserId; private System.ComponentModel.IContainer components;

public MainForm()

{

InitializeComponent();

}

///<summary>

///Clean up any resources being used.

///</summary>

protected override void Dispose( bool disposing )

{

if( disposing )

{

if (components != null)

{

components.Dispose();

}

}

base.Dispose( disposing );

}

#region Windows Form Designer generated code

///<summary>

///Required method for Designer support — do not modify

///the contents of this method with the code editor.

///</summary>

private void InitializeComponent()

{

this.components = new System.ComponentModel.Container(); System.Resources.ResourceManager resources = new System.Resources.ResourceManager(typeof

(MainForm));

this.toolBar = new System.Windows.Forms.ToolBar(); this.btnViewUsers = new System.Windows.Forms.ToolBarButton(); this.btnEditUsers = new System.Windows.Forms.ToolBarButton();

this.toolBoxIcons = new System.Windows.Forms.ImageList(this.components); this.lstViewUsers = new System.Windows.Forms.ListView();

this.colUserName = new System.Windows.Forms.ColumnHeader(); this.colUserRole = new System.Windows.Forms.ColumnHeader(); this.colUserId = new System.Windows.Forms.ColumnHeader(); this.SuspendLayout();

//

// toolBar

//

this.toolBar.Buttons.AddRange(new System.Windows.Forms.ToolBarButton[] { this.btnViewUsers,

this.btnEditUsers}); this.toolBar.DropDownArrows = true; this.toolBar.ImageList = this.toolBoxIcons; this.toolBar.Location = new System.Drawing.Point(0, 0); this.toolBar.Name = "toolBar"; this.toolBar.ShowToolTips = true;

this.toolBar.Size = new System.Drawing.Size(424, 28); this.toolBar.TabIndex = 0;

this.toolBar.ButtonClick += new System.Windows.Forms.ToolBarButtonClickEventHandler (this.toolBar_ButtonClick);

//

//btnViewUsers

this.btnViewUsers.ImageIndex = 0; this.btnViewUsers.Tag = "view";

this.btnViewUsers.ToolTipText = "Вывести список пользователей";

//btnEditUsers

//

this.btnEditUsers.ImageIndex = 1; this.btnEditUsers.Tag = "edit";

this.btnEditUsers.ToolTipText = "Редактировать роль пользователя";

//

// toolBoxIcons

//

this.toolBoxIcons.ImageSize = new System.Drawing.Size(16, 16); this.toolBoxIcons.ImageStream = ((System.Windows.Forms.ImageListStreamer)

(resources.GetObject("toolBoxIcons.ImageStream")));

this.toolBoxIcons.TransparentColor = System.Drawing.Color.Transparent;

//

// lstViewUsers

//

this.lstViewUsers.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { this.colUserName,

this.colUserRole,

this.colUserId}); this.lstViewUsers.Cursor = System.Windows.Forms.Cursors.Hand; this.lstViewUsers.Dock = System.Windows.Forms.DockStyle.Fill; this.lstViewUsers.FullRowSelect = true; this.lstViewUsers.GridLines = true; this.lstViewUsers.Location = new System.Drawing.Point(0, 28); this.lstViewUsers.MultiSelect = false;

this.lstViewUsers.Name = "lstViewUsers"; this.lstViewUsers.Size = new System.Drawing.Size(424, 238); this.lstViewUsers.SmallImageList = this.toolBoxIcons; this.lstViewUsers.TabIndex = 1;

this.lstViewUsers.View = System.Windows.Forms.View.Details;

//

//colUserName

this.colUserName.Text = "Имя пользователя"; this.colUserName.Width = 125;

//colUserRole

//

this.colUserRole.Text = "Роль пользователя"; this.colUserRole.Width = 125;

//

//colUserId

this.colUserId.Text = "Уникальный идентификатор"; this.colUserId.Width = 175;

//MainForm

//

this.AutoScaleBaseSize = new System.Drawing.Size(5, 13); this.ClientSize = new System.Drawing.Size(424, 266); this.Controls.Add(this.lstViewUsers); this.Controls.Add(this.toolBar);

this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); this.Name = "MainForm";

this.Text = "Ролевая безопасность";

this.Load += new System.EventHandler(this.MainForm_Load); this.ResumeLayout(false);

}

#endregion

///<summary>

///The main entry point for the application.

///</summary>

[STAThread]

static void Main()

{

Application.Run(new MainForm());

}

private void MainForm_Load(object sender, System.EventArgs e)

{

// Получаем имя пользователя. LogInForm login = new LogInForm();

if(login.ShowDialog() != DialogResult.OK)

{

// Если пользователь отменил ввод имени, закрываем приложение this.Close();

return;

}

try

{

// Создаем объекты IIdentity и IPrincipal

CustomIdentity identity = new CustomIdentity(login.txbUserName.Text); CustomPrincipal principal = new CustomPrincipal(identity); Thread.CurrentPrincipal = principal;

this.ValidateUser();

}

catch(Exception ex)

{

// Обрабатываем исключения и закрываем приложение.

MessageBox.Show("Во время выполнения приложения возникла ошибка: "+ex.Message,

"Ошибка");

this.Close();

return;

}

}

///<summary>

///Изменяем пользовательский интерфейс в зависимости от роли пользователя.

///</summary>

private void ValidateUser()

{

CustomPrincipal principal = Thread.CurrentPrincipal as CustomPrincipal; if(principal.IsInRole("operator"))

{

// Если роль пользователя — operator, скрываем функциональность. btnEditUsers.Enabled = false;

btnViewUsers.Enabled = false;

}

if(principal.IsInRole("manager"))

{

// Для роли пользователя manager скрываем возможности изменения роли пользователя. btnEditUsers.Enabled = false;

}

}

private void toolBar_ButtonClick(object sender, System.Windows.Forms.ToolBarButtonClickEventArgs e)

{

//Проверяем, какая кнопка была нажата, и

//выполняем соответствующее действие. switch(e.Button.Tag.ToString())

{

case "view": this.ViewUsers(); break;

case "edit": this.EditUser(); break;

}

}

///<summary>

///Выводим пользователей на экран.

///</summary>

private void ViewUsers()

{

lstViewUsers.Items.Clear();

XmlTextReader xmlReader = new XmlTextReader("Users.xml"); xmlReader.WhitespaceHandling = WhitespaceHandling.None; while(xmlReader.Read())

{

//Считываем данные из XML-файла, представляем их в виде

//строки элемента управления ListView if(xmlReader["name"] == null)

continue;

ListViewItem item = new ListViewItem(new

string[]{xmlReader["name"], xmlReader["role"], xmlReader["id"]}, 0);

lstViewUsers.Items.Add(item);

}

xmlReader.Close();

}

///<summary>

///Изменяем выбранного пользователя.

///</summary>

private void EditUser()

{

if(lstViewUsers.SelectedItems.Count == 0)

{

MessageBox.Show("Вы дожны выбрать пользователя.", "Сообщение приложения");

}

else

{

string userName = lstViewUsers.SelectedItems[0].Text; EditUserForm edit = new EditUserForm(userName); if(edit.ShowDialog() != DialogResult.OK)

return;

// Считываем новую роль.

string newRole = edit.cmbRole.SelectedItem.ToString(); // Обновляем файл XML новыми данными.

XmlDocument doc = new XmlDocument();

StreamReader reader = new StreamReader("Users.xml"); doc.LoadXml(reader.ReadToEnd());

reader.Close();

XmlElement root = doc.DocumentElement; foreach(XmlNode child in root.ChildNodes)

{

if(child.Attributes["name"].Value == userName)

{

child.Attributes["role"].Value = newRole; break;

}

}

doc.Save("Users.xml");

this.ViewUsers();

}

}

}

}

Листинг 10.7.

При запуске приложения доступ к главной форме будет блокироваться до прохождения авторизации (рис.рис. 10.16).

Рис. 10.16. Авторизация пользователя

Добавьте новую Windows-форму в проект и назовите ее LoginForm.cs. Листинг этой формы:

using System;

using System.Drawing; using System.Collections;

using System.ComponentModel; using System.Windows.Forms;

namespace CustomSecurity

{

///<summary>

///Форма ввода имени пользователя.

///</summary>

public class LogInForm : System.Windows.Forms.Form

{

// Обратите внимание на то, что модификатору доступа элемента

// управления txbUserName установлено значение public. Это сделано для того, чтобы // можно было из другой формы получить введенный в него текст.

public System.Windows.Forms.TextBox txbUserName; private System.Windows.Forms.Button btnCancel; private System.Windows.Forms.Button btnOk; private System.Windows.Forms.Label lblUserName;

///<summary>

///Required designer variable.

///</summary>

private System.ComponentModel.Container components = null;

public LogInForm()

{

//

// Required for Windows Form Designer support

//

InitializeComponent();

//

// TODO: Add any constructor code after InitializeComponent call

//

}

///<summary>

///Clean up any resources being used.

///</summary>

protected override void Dispose( bool disposing )

{

if( disposing )

{

if(components != null)

{

components.Dispose();

}

}

base.Dispose( disposing );

}

#region Windows Form Designer generated code

private void InitializeComponent()

{

this.txbUserName = new System.Windows.Forms.TextBox(); this.btnCancel = new System.Windows.Forms.Button(); this.btnOk = new System.Windows.Forms.Button(); this.lblUserName = new System.Windows.Forms.Label(); this.SuspendLayout();

//

//txbUserName

this.txbUserName.Location = new System.Drawing.Point(16, 32); this.txbUserName.Name = "txbUserName";

this.txbUserName.Size = new System.Drawing.Size(312, 20); this.txbUserName.TabIndex = 0;

this.txbUserName.Text = "";

//btnCancel

//

this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; this.btnCancel.Location = new System.Drawing.Point(152, 80); this.btnCancel.Name = "btnCancel";

this.btnCancel.TabIndex = 1; this.btnCancel.Text = "Отмена";

//

//btnOk

this.btnOk.Location = new System.Drawing.Point(248, 80); this.btnOk.Name = "btnOk";

this.btnOk.TabIndex = 2; this.btnOk.Text = "ОК";

this.btnOk.Click += new System.EventHandler(this.btnOk_Click);

//lblUserName

//

this.lblUserName.Location = new System.Drawing.Point(16, 8); this.lblUserName.Name = "lblUserName";

this.lblUserName.Size = new System.Drawing.Size(216, 24); this.lblUserName.TabIndex = 3;

this.lblUserName.Text = "Введите имя пользователя:";

//

// LogInForm

//

this.AcceptButton = this.btnOk;

this.AutoScaleBaseSize = new System.Drawing.Size(5, 13); this.CancelButton = this.btnCancel;

this.ClientSize = new System.Drawing.Size(342, 116); this.Controls.Add(this.lblUserName); this.Controls.Add(this.btnOk); this.Controls.Add(this.btnCancel); this.Controls.Add(this.txbUserName);

this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow; this.Name = "LogInForm";

this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; this.Text = "Авторизация";

this.ResumeLayout(false);

}

#endregion

private void btnOk_Click(object sender, System.EventArgs e)

{

//Устанавливаем положительный результат выполнения

//и закрываем форму.

this.DialogResult = DialogResult.OK; this.Close();

}

}

}

Листинг 10.8.

Последняя форма, которая будет использована в нашем проекте, — EditUserForm, изменяющая роль пользователей (рис. 10.17).

Рис. 10.17. Форма EditUserForm

Листинг этой формы:

using System;

using System.Drawing; using System.Collections;

using System.ComponentModel; using System.Windows.Forms;

namespace CustomSecurity

{

///<summary>

///Форма изменения роли пользователя

///</summary>

public class EditUserForm : System.Windows.Forms.Form

{

private System.Windows.Forms.Label lblName; private System.Windows.Forms.Label lblRole; public System.Windows.Forms.ComboBox cmbRole; private System.Windows.Forms.Label lblUserName; private System.Windows.Forms.Button btnCancel; private System.Windows.Forms.Button btnEdit;

///<summary>

///Required designer variable.

///</summary>

private System.ComponentModel.Container components = null; private string UserName;

//Обратите внимание на то, что у формы переопределен конструктор.

//Это сделано для передачи форме имени пользователя,

//роль которого необходимо изменить.

public EditUserForm(string userName)

{

UserName = userName; InitializeComponent();

}

///<summary>

///Clean up any resources being used.

///</summary>

protected override void Dispose( bool disposing )

{

if( disposing )

{

if(components != null)

{

components.Dispose();

}

}

base.Dispose( disposing );

}

#region Windows Form Designer generated code

///<summary>

///Required method for Designer support — do not modify

///the contents of this method with the code editor.

///</summary>

private void InitializeComponent()

{

System.Resources.ResourceManager resources = new System.Resources.ResourceManager(typeof

(EditUserForm));

this.lblName = new System.Windows.Forms.Label(); this.lblRole = new System.Windows.Forms.Label(); this.btnCancel = new System.Windows.Forms.Button(); this.btnEdit = new System.Windows.Forms.Button(); this.cmbRole = new System.Windows.Forms.ComboBox(); this.lblUserName = new System.Windows.Forms.Label(); this.SuspendLayout();

//

// lblName

//

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]