Аутентификация и разрешения

192

Если Web-cepвep требует аутентификации пользователя, можно создать удостоверение личности пользователя и передать его Web-запросу. При этом полезны следующие интерфейсы и классы: ICredentials, NetworkCredential и CredentialCache.

Для аутентификации пользователя создадим объект типа NetworkCredential. Этот класс обеспечивает информацию с целью удостоверения личности пользователя для базовой аутентификации, аутентификации на основе дайджестов, NTLM и Kerberos.

Конструктору класса NetworkCredential можно передать имя пользователя, пароль и дополнительно домен, разрешающий доступ пользователя:

NetworkCredential credential = 
        new NetworkCredential("Alex", "12345", "alex.professorweb.ru");

Для авторизации пользователя эту информацию удостоверения личности можно установить в свойстве Credentials класса WebRequest:

WebRequest request = WebRequest.Create("http://professorweb.ru/");
request.Credentials = credential;

Если нужна разная информация удостоверений личности для разных URI, можно использовать класс CredentialCache, как показано в следующем коде. С таким кэшем также определяется тип аутентификации для конкретного соединения. Здесь используется базовая аутентификация для Web-сайта www.unsecure.com и аутентификация на основе дайджестов для Web-сайта www.moresecure.com, для которого через сеть посылается не пароль, а хеш-код:

CredentialCache ccache = new CredentialCache();

ccache.Add(new Uri("http://www.unsecure.com"), "Basic", 
                new NetworkCredential("user", "password"));

ccache.Add(new Uri("http://www.moresecure.com"), "Digest",
                new NetworkCredential("user", "password", "domain"));

Разрешения

Всякий раз когда используются сетевые классы, требуются разрешения. Для вопросов сетевого обмена рассмотрим три типа разрешения.

Разрешение DnsPermission требуется для поиска имени DNS с помощью класса Dns. WebPermission используется классами из пространства имен System.Net, которые отправляют данные в Интернет и получают данные с помощью URI. SocketРеrmission используется для приема данных на локальном сокете или соединения с хостом через транспортный протокол.

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

DnsPermission

Когда используется класс Dns для поиска IP-адреса, требуется разрешение DnsPermission. Для него различаем только значения "признать" и "отвергнуть". Запросы DNS или абсолютно не ограничиваются, или не разрешаются совсем.

WebPermission

WebPermission требуется для таких классов, как WebRequest и WebResponse, чтобы отправлять данные в Интернет и получать их из Интернета.

В этом случае различаются разрешения "согласиться" (Accept) и "соединиться" (Connect). Разрешение Accept нужно для URI, используемых внутри классов и методов. Клиентским приложениям, использующим URI для соединения с сервером, требуется полномочие Connect. У класса WebPermission также есть список URI, с которыми можно соединиться, и список URI, с которыми можно согласиться.

SocketPermission

Разрешения SocketРеrmission нужны для классов сокетов из пространства имен System.Net.Sockets. Это разрешение — самое гибкое из трех классов сетевых разрешений.

Для серверных приложений, ожидающих запросы на соединения от клиентов, в конструктор передается значение перечисления NetworkAccess.Accept; клиентские приложения, соединяющиеся с серверами, используют значение NetworkAccess.Connect. Можем ограничить соединение конкретными хостами и номерами портов и определить используемый транспортный протокол.

Использование атрибутов разрешения

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

Если для получения данных из Интернета используется класс WebRequest, требуется разрешение WebPermission. Можно отметить классы и методы, требующие разрешения, атрибутом WebPermission (реализованным в классе WebPermissionAttribute) следующим образом:

[WebPermission(System.Security.Permissions.SecurityAction.Demand,
        ConnectPattern="www.professorweb.ru")]
class PermissionDemo
{
   ...

В данном случае исключение SecurityException возникает, как только создается экземпляр класса PermissionDemo. Если хотим, чтобы эта проверка выполнялась при старте программы, можно применить атрибут WebPermission ко всей сборке:

[assembly: WebPermission(System.Security.Permissions.SecurityAction.Demand,
        ConnectPattern = "www.professorweb.ru")]

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

Со всеми атрибутами разрешения конструктору передается значение перечисления SecurityAction. Здесь рассмотрим только самые важные значения перечисления:

Перечисление SecurityAction
Значения перечисления Описание
Demand и Deny Значения перечисления SecurityAction.Demand и SecurityAction.Deny можно использовать с классами и методами. Значением Demand указывается, что классу или методу требуется разрешение, значение Deny определяет, что это разрешение не нужно.
RequestMinimum, RequestOptional и RequestRefuse Значением перечисления Requestxxx можно пользоваться только в контексте сборки, его нельзя указывать с классами и методами. RequestMinimum определяет, что это разрешение обязательно для использования программы.

Значением RequestOptional сообщается, что программа может выполнить некоторую полезную работу без этого разрешения. В этом случае надо постепенно обработать исключение SecurityException.

Значение RequestRefuse определяет, что это разрешение не нужно. Это значение используется в тех случаях, когда возможно неправильное применение разрешения, например вызов сборок, для которых у нас нет исходных текстов и которым мы не доверяем полностью.

С атрибутом WebPermission можно в дополнение к SecurttyAction установить следующие свойства:

Accept и AcceptPattern

В свойстве Accept определяется URI ресурса для использования с классом, методом или сборкой, к которым применен этот атрибут. В свойстве AcceptPattern указывается регулярное выражение, чтобы разрешить или запретить доступ к URI.

Connect и ConnectPattern

Два свойства ConnectXX аналогичны свойствам AcceptXX, но отличаются тем, что применяются для строки соединения с URI.

В классе SocketPermissionAttribute определены следующие дополнительные свойства:

Access

В этом свойстве определяется допустимый метод доступа к сети. Допустимы только два: Accept и Connect. Значение Accept используется для серверного приложения, слушающего и принимающего соединения клиентов, а значение Connect предназначено для клиента, соединяющегося с сервером.

Host

В свойстве Host с использованием синтаксиса DNS или IP-адреса устанавливается имя хоста, к которому относится разрешение.

Port

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

Transport

С помощью свойства Transport ограничиваются сетевые соединения конкретным транспортным протоколом. Возможные значения: All, ConnectionLess, CormectionOriented, Tcp и Udp. Значение ConnectionLess позволяет использовать все протоколы, не требующие устанавливать соединения, например UDP; значение ConnectionOriented позволяет использовать протоколы, ориентированные на установление соединения, например TCP.

Пройди тесты
Лучший чат для C# программистов