- •А.А. Волосевич
- •2. Базовые технологии платформы .Net 5
- •2. Базовые технологии платформы .Net 4
- •2. Базовые технологии платформы .Net
- •2.1. Работа с Числами
- •2.2. Дата и время
- •2.3. Работа со строками и текстом
- •2.4. Преобразование информации
- •2.5. Отношения равенства и порядка
- •Сравнение для выяснения равенства
- •Сравнение для выяснения порядка
- •2.6. Жизненный цикл объектов
- •Алгоритм «сборки мусора»
- •Финализаторы и интерфейс iDisposable
- •2.7. Перечислители и итераторы
- •2.8. Интерфейсы стандартных коллекций
- •2.9. Массивы и класс system.Array
- •2.10. Типы для работы с коллекциями-списками
- •2.11. Типы для работы с коллекциями-множествами
- •2.12. Типы для работы с коллекциями-словарями
- •2.13. Типы для создания пользовательских коллекций
- •2.14. Технология linq to objects
- •1. Оператор условия Where().
- •2. Операторы проекций.
- •3. Операторы упорядочивания.
- •4. Оператор группировки GroupBy().
- •5. Операторы соединения.
- •6. Операторы работы с множествами.
- •7. Операторы агрегирования.
- •8. Операторы генерирования.
- •9. Операторы кванторов и сравнения.
- •10. Операторы разбиения.
- •11. Операторы элемента.
- •12. Операторы преобразования.
- •2.15. Работа с объектами файЛовой системы
- •2.16. Ввод и вывод информации
- •Потоки данных и декораторы потоков
- •2. Классы для работы с потоками, связанными с хранилищами.
- •3. Декораторы потоков.
- •4. Адаптеры потоков.
- •Адаптеры потоков
- •2.17. Основы xml
- •2.18. Технология linq to xml
- •Создание, сохранение, загрузка xml
- •Запросы, модификация и трансформация xml
- •Пространства имен xml
- •2.19. ДОполнительные возможности обработки xml
- •2.20. Сериализация
- •Сериализация времени выполнения
- •Сериализация контрактов данных
- •2.21. Состав и взаимодействие сборок
- •2.22. Метаданные и получение информации о типах
- •2.23. Позднее связывание и кодогенерация
- •2.24. Динамические типы
- •2.25. Атрибуты
- •2.26. Файлы конфигуРации
- •2.27. Основы мНогопоточноГо программирования
- •2.28. Синхронизация потоков
- •2.29. Библиотека параллельных расширений
- •Параллелизм на уровне задач
- •Параллелизм при императивной обработке данных
- •Параллелизм при декларативной обработке данных
- •Обработка исключений и отмена выполнения задач
- •Коллекции, поддерживающие параллелизм
- •2.30. Асинхронный вызов методов
- •2.31. Процессы и домены
- •2.32. Безопасность
- •Разрешения на доступ
- •Изолированные хранилища
- •Криптография
- •2.33. Диагностика
2.31. Процессы и домены
Любому запущенному приложению в операционной системе соответствует некий процесс. Процесс образует границы приложения, выделяя для приложения изолированное адресное пространство и поддерживая один или несколько потоков выполнения. Для работы с процессами в платформе .NET имеется класс System.Diagnostics.Process. Используя свойства этого класса можно получить информацию о текущем процессе, а также всех процессах системы.
Process current = Process.GetCurrentProcess();
foreach(Process p in Process.GetProcesses())
{
Console.WriteLine("{0} {1} {2}",
p.Id, p.ProcessName, p.StartTime);
}
Класс Process позволяет управлять процессами (при наличии соответствующих привилегий). В следующем примере запускается приложение «Блокнот», которое завершается через 5 секунд.
Process p = Process.Start("notepad.exe");
Thread.Sleep(5000);
p.Kill();
Платформа .NET вводит дополнительный уровень изоляции кода, называемый доменом приложения. Домены существуют внутри процессов и содержат загруженные сборки. Любой процесс запускает при старте домен по умолчанию, однако домены могут создаваться и уничтожаться в ходе работы в рамках процесса. Домены обеспечивают приемлемый уровень изоляции кода, но их создание менее затратно, чем создание отдельных процессов. Кроме того, домен можно уничтожить, не нарушая целостность работы всего процесса.
Домены приложений инкапсулированы в объектах класса System.AppDomain. Статическое свойство CurrentDomain позволяет получить информацию о текущем домене, а статические методы наподобие CreateDomain() ‑ создать новый домен в рамках текущего процесса. После создания домена в него можно программно загрузить сборки, используя экземплярный метод. Выгрузить отдельные сборки из домена нельзя. Можно только выгрузить весь домен:
AppDomain newDomain = AppDomain.CreateDomain("nd");
newDomain.Load("assemblyName");
AppDomain.Unload(newDomain);
Домены содержат методы для создания экземпляров объектов требуемых типов (например, CreateInstance()). Однако доступ к созданным экземплярам нетривиален – фактически, это межпрограммное взаимодействия, для которого существую специальные технологии.
2.32. Безопасность
В параграфе обсуждаются следующие аспекты безопасности в .NET: разрешения на доступ, изолированные хранилища, криптография.
Разрешения на доступ
Рассмотрим вопросы, связанные с разрешением на доступ к ресурсам. Начнем с анализа терминологии. Под пользователем (user) будем понимать физическое лицо или систему. Личность (identity) – это информация о пользователе, связанная с системой безопасности. Принципал (principal) – личность, рассматриваемая с точки зрения определенной задачи обеспечения безопасности.
В платформе .NET определён интерфейс IIdentity, используемый классами описания личности:
public interface IIdentity
{
string AuthenticationType { get; }
bool IsAuthenticated { get; }
string Name { get; }
}
Свойство Name – это имя пользователя. Свойство IsAuthenticated используется для различения аутентифицированных и анонимных пользователей. Свойство AuthenticationType позволит выяснить тип аутентификации.
Для описания принципалов существуют два основных класса: WindowsPrincipal и GenericPrincipal. Первый класс представляет принципала с точки зрения операционной системы, а второй класс – это база для реализации собственных принципалов. Оба класса реализуют интерфейс IPrincipal:
public interface IPrincipal
{
IIdentity Identity { get; }
bool IsInRole(string role);
}
Операционная система содержит встроенные механизмы обеспечения безопасности доступа к ресурсам (файлам, каталогам, процессам). При запуске любого процесса система помещает в контекст потока выполнения специальный маркер безопасности, описывающий личность пользователя, выполнившего запуск. Маркер безопасности копируется во все потоки, порождённые процессом. Если код потока выполняет доступ к защищенному ресурсу, система извлекает маркер безопасности и проверяет права пользователя на доступ.
Механизмы безопасности .NET строятся поверх соответствующих механизмов операционной системы. Как и операционная система, CLR позволяет связать с потоком выполнения определенного пользователя. Принципал этого пользователя будет доступен через свойство Thread.CurrentPrincipal. Однако значение этого свойства не обязательно совпадает с принципалом операционной системы. Например, в консольном приложении Thread.CurrentPrincipal по умолчанию вообще не задан, хотя, безусловно, маркер безопасности и соответствующий принципал ОС в нём присутствует. В следующем примере кода демонстрируется анализ данных личности и принципала. Чтобы связать маркер безопасности операционной системы с принципалом CLR, используется специальный приём.
// получаем данные о пользователе Windows
WindowsIdentity winUser = WindowsIdentity.GetCurrent();
Console.WriteLine(winUser.Name);
Console.WriteLine(winUser.IsGuest);
// изменяем политику безопасности по умолчанию,
// чтобы связать пользователя Windows и Thread.CurrentPrincipal
AppDomain.CurrentDomain.SetPrincipalPolicy(
PrincipalPolicy.WindowsPrincipal);
// получаем даннные из Thread.CurrentPrincipal
IPrincipal pr = Thread.CurrentPrincipal;
Console.WriteLine(pr.Identity.Name);
Обладая информацией о пользователе, можно решать, есть ли у этого пользователя право производить заданные действия. При этом удобным оказывается механизм ролей, связывающий пользователя с определённой группой (или группами)1.
// выполняем приведение типов, чтобы использовать
// перегруженный вариант IsInRole()
var pr = (WindowsPrincipal) Thread.CurrentPrincipal;
Console.WriteLine(pr.IsInRole(WindowsBuiltInRole.Administrator) ?
"Действия разрешены" : "Действия запрещены");
В примере вместо работы со строковым именем роли использовалось перечисление WindowsBuiltInRole, описывающее стандартные роли Windows.
В платформе .NET можно контролировать не только доступ к внешним ресурсам, но и использовать ограничения на доступ к коду. Соответствующая подсистема носит название Code Access Security (CAS). Права доступа к коду описываются разрешениями, представленными как объекты классов, производных от CodeAccessPermission. Наиболее важным методом разрешения является метод Demand(). Он проверяет стек вызова на наличие прав выполнения кода и в случае их отсутствия генерирует исключение SecurityException. Пусть, например, создаётся метод, обрабатывающий с файлы, и необходимо убедится, что у кода, вызывающего этот метод, есть права на работу с файлами. В этом случае следует воспользоваться классом FileIOPermission и разместить в начале метода такой код:
new FileIOPermission(PermissionState.None).Demand();
Так как подобный код зачастую располагаются в начале тела метода, для всех Permission–классов существуют одноименные атрибуты, применяемые к методам и позволяющие настроить разрешения декларативно1.
[FileIOPermission(SecurityAction.Demand)]
private void ActionWithFiles() { . . . }
Объекты разрешения могут комбинироваться в наборы, с которыми можно работать, как с множествами.
Каким образом вызывающий код получает некие разрешения? Все разрешения, которые имеет код, образуют политику безопасности. Политика безопасности для сборки определяет средой выполнения по имени сборки, месту, откуда загружена сборка, и прочим параметрам. При необходимости политика безопасности может быть задана как часть конфигурации сборки.