Партнерка на США и Канаду по недвижимости, выплаты в крипто
- 30% recurring commission
- Выплаты в USDT
- Вывод каждую неделю
- Комиссия до 5 лет за каждого referral
Разработка приложений в среде. NET
Тема №5. Разработка WCF-сервисов
5. Разработка WCF-сервисов
В версии.NET Framework 3.0 был представлен API-интерфейс, специально предназначенный для построения распределенных систем, который имеет название Windows Communication Foundation (WCF). В отличие от других распределенных API, которые часто применялись в прошлом (DCOM, .NET Remoting, веб-службы XML (ASMX) и т. п.), WCF предлагает единую, унифицированную и расширяемую программную объектную модель, которая может использоваться для взаимодействия с множеством ранее разрозненных технологий.
Главная проблема состоит в том, что реализации перечисленных веб-сервисов, созданных крупными компаниями (Microsoft, IBM, Sun), были не на 100% совместимы между собой. Вполне очевидно, что это было проблемой, учитывая, что основной целью веб-сервисов является достижение высокой степени взаимодействия между платформами и операционными системами.
Чтобы гарантировать возможность взаимодействия веб-сервисов, группа под названием World Wide Web Consortium (W3C; http://www. w3.org) и организация Web Services Interoperability Organization (WS-I; http://www.ws-i.org) начали разрабатывать несколько спецификаций, определяющих детали, согласно которым поставщики программного обеспечения должны строить библиотеки ПО для разработки веб-сервисов, чтобы обеспечить совместимость.
Все эти спецификации получили общее имя WS-* и охватили вопросы безопасности, вложений, описание веб-сервисов (через язык описания веб-сервисов WSDL (Web Description Language)), политики, форматы SOAP и массу прочих деталей.
Реализация Microsoft, учитывающая большую часть этих стандартов (как для управляемого, так и неуправляемого кода), встроена в набор инструментов Web Services Enhancements (WSE) 3.0.
При построении приложения службы WCF не приходится напрямую использовать сборки, которые являются частью набора инструментов WSE 3.0. Вместо этого, если создается служба WCF, использующая привязку на базе HTTP, то все эти спецификации WS-* предоставляются в готовом виде (в точности те, что основаны на выбранной привязке).
Широкий спектр распределенных технологий весьма затрудняет выбор правильного инструмента для работы. Ситуация еще более усложняется из-за того, что некоторые из этих технологий имеют перекрывающуюся функциональность.
Даже когда разработчик .NET выбрал технологию, которая кажется «правильной» для текущей задачи, построение, сопровождение и конфигурирование такого приложения будет, по меньшей мере, сложным. Каждый API-интерфейс имеет собственную программную модель, собственный уникальный набор средств конфигурирования и т. д.
Из-за этого до появления .NET 3.0 было очень трудно «подключить» распределенные API-интерфейсы без написания существенного объема специальной инфраструктуры.
Например, если бы мы построили систему с использованием API-интерфейсов. NET Remoting, а позднее решились применить веб-службы XML, как более подходящее решение, то пришлось бы практически полностью перепроектировать кодовую базу.
WCF— инструмент распределенных вычислений, который интегрирует все эти прежние независимые технологии распределенной обработки в один стройный API-интерфейс, представленный, прежде всего, пространством имен System. ServiceModel. С помощью WCF можно предоставлять эти службы вызывающему коду, применяя для этого широкое разнообразие приемов. Например, при создании приложения, где все подключенные машины работают под управлением Windows, можно использовать различные протоколы TCP/IP для обеспечения максимально возможной производительности. Те же службы также могут быть представлены с применением протоколов на основе веб-сервисов XML, чтобы позволить внешним клиентам использовать их функциональность, независимо от языка программирования или операционной системы.
Учитывая тот факт, что WCF позволяет выбрать правильный протокол для выполнения работы, используя общую программную модель, мы обнаруживаем, что достаточно просто подключить и запустить низкоуровневые механизмы распределенного приложения. В большинстве случаев это можно делать без перекомпиляции или повторного развертывания клиентского/серверного программного обеспечения, поскольку низкоуровневые детали часто задаются в конфигурационных файлах приложения (как в .NET Remoting).
Возможность взаимодействия и интеграция различных API-интерфейсов — это только два (хотя и важных) аспекта WCF. В дополнение WCF предлагает богатую фабрику программного обеспечения, которая дополняет технологии удаленной разработки, представленные WFC. Главные средства WCF:
• Поддержка как строго типизированных, так и не типизированных сообщений. Этот подход позволяет приложениям .NET эффективно разделять типы, в то время как ПО, созданное с использованием других платформ (J2EE) может потреблять потоки слабо типизированного XML.
• Поддержка нескольких привязок (простой HTTP, TCP, MSMQ и именованные конвейеры), позволяющая выбирать наиболее подходящий механизм для транспортировки сообщений туда и обратно.
• Поддержка актуальных спецификаций веб-служб (WS-*).
• Полностью интегрированная модель безопасности, охватывающая как «родные» протоколы безопасности Windows и .NET, так и многочисленные нейтральные технологии защиты, построенные на стандартах веб-сервисов.
• Поддержка технологий хранения состояния сеансов, а также поддержка однонаправленных сообщений без состояния.
Каким бы впечатляющим ни был этот список, на самом деле он лишь поверхностно касается функциональности, предлагаемой WCF. Инструмент WCF также предоставляет средства трассировки и протоколирования, счетчики производительности, модель публикации и подписи на события, поддержку транзакций и многое другое.
Еще одно преимущество WCF состоит в том, что он базируется на принципах дизайна, установленном сервис-ориентированной архитектурой (service-oriented architecture — SOA). Это способ проектирования распределенных систем, где несколько автономных служб работают совместно, передавая друг другу сообщения (речь идет либо о сетевых машинах, либо о просто двух процессах на одной и той же машине) с использованием четко определенных интерфейсов.
В мире WCF эти «четко определенные интерфейсы» обычно создаются с использованием действительных интерфейсных типов CLR. Однако в более общем смысле интерфейс службы просто описывает набор членов, которые могут быть вызваны внешними клиентами.
Когда проектировался WCF, команда его разработчиков делала это на основе четырех принципов проектирования SOA. Хотя данные принципы реализуются автоматически, просто при построении приложения WCF, понимание этих четырех кардинальных правил дизайна SOA может помочь использовать WCF в дальнейшей перспективе.
Принцип 1: границы установлены явно
Этот принцип подчеркивает тот факт, что функциональность WCF-сервиса выражается через четко определенные интерфейсы (т. е. описания каждого элемента, его параметров и возвращаемых значений). Единственный способ, которым внешний клиент может связаться со службой WCF, — через интерфейс, при этом оставаясь в неведении о деталях ее внутренней реализации. Внимательному слушателю/читателю это должно напомнить о паттерне проектирования Фасад.
Принцип 2: сервисы автономны
Говоря о сервисах, как об «автономных» сущностях, мы имеем в виду тот факт, что каждый сервис WCF является по возможности отдельным «кусочком». Автономный сервис должен быть независимым от проблем с версиями, проблем развертывания и проблем инсталляции. Чтобы помочь в продвижении этого принципа, мы должны вспомнить о важнейшем аспекте программирования на базе интерфейсов. Как только интерфейс внедрен, он никогда не должен изменяться (иначе мы разрушим существующие клиенты). Когда мы захотим расширить функциональность сервиса WCF, мы просто напишем новый интерфейс, который моделирует необходимую функциональность.
Принцип 3: сервисы взаимодействуют через контракт, а не реализацию
Это еще один побочный продукт программирования на основе интерфейсов — состоит в том, что реализация деталей сервиса WCF (на каком языке она написана, как именно выполняет свою работу, и т. п.) не касается вызывающего ее внешнего клиента. Клиенты WCF взаимодействуют с сервисами исключительно через их открытые интерфейсы. Более того, если элементы сервиса представляют сложные специальные типы, они должны быть полностью детализированы в виде контракта данных, гарантируя, что клиенты смогут отобразить содержимое на определенную структуру данных.
Принцип 4: совместимость сервисов базируется на политике
Поскольку интерфейсы CLR предоставляют строго типизированные контракты всем клиентам WCF, а также могут быть использованы для генерации соответствующего документа WSDL на основе выбранной привязки, то важно указать на то, что интерфейсы/WSDL сами по себе недостаточно выразительны, чтобы детализировать аспекты того, что способна делать служба. Учитывая это, SOA позволяет определять «политики», которые еще более проясняют семантику сервиса (скажем, требования безопасности, применяемые для общения с сервисом). Используя эти политики, можно отделять низкоуровневые синтаксические описания службы (предоставляемые интерфейсы) от семантических деталей их работы и способов их вызова.
4.1 Основные сборки WCF
![]() |
WCF представлена набором сборок .NET, инсталлированных в GAC. В таблице описана общая роль основных сборок WCF, которые понадобится применять почти в любом приложении WCF.
Эти две сборки определяют ряд пространств имен и типов. Хотя за всеми деталями стоит обратиться к документации по .NET Framework 4.0, в таблице описаны роли некоторых важнейших пространств имен, о которых следует знать.

При построении распределенной системы WCF обычно создаются три взаимосвязанных сборки.
• Сборка сервиса WCF. Эта библиотека *.dll содержит классы и интерфейсы, представляющие общую функциональность, которая предоставляется внешним клиентам.
• Хост сервиса WCF. Этот программный модуль — сущность, которая принимает в себе сборку сервиса WCF.
• Клиент WFC. Это приложение, которое обращается к функциональности сервису через прокси-классы.
Как уже упоминалось, сборка сервиса WCF — это библиотека классов .NET, содержащая в себе множество контрактов WCF и их реализаций. Одно ключевое отличие состоит в том, что контрактные интерфейсы оснащены разнообразными атрибутами, которые управляют представлением типа данных, тем, как исполняющая система WCF взаимодействует с представленными типами, и т. д.
Вторая сборка — хост WCF может быть любой исполняемой программой. WCF настраивается таким образом, что сервисы могут быть легко представлены приложениями любого типа (Windows Forms, сервис ОС, приложения WPF и т. д.). При построении специального хоста применяется тип ServiceHost и связанный с ним файл *.сonfig, который содержит детали, касающиеся механизмов серверной стороны, которые вы хотите использовать. Однако если в качестве хоста для службы WCF применяется IIS, то нет необходимости в программном построении специального хоста, поскольку IIS использует «за кулисами» тип ServiceHost.
Последняя сборка представляет клиент, который осуществляет вызовы службы WCF. Как и можно было ожидать, этим клиентом может быть приложение.NET любого типа. Подобно хосту, клиентское приложение также обычно использует файл *.config клиентской стороны, определяющий все клиентские механизмы.
![]() |
На рисунке показаны отношения между этими тремя взаимосвязанными сборками WCF. Не показаны некоторые низкоуровневые детали, реализующие все необходимые внутренние механизмы. Эти низкоуровневые детали чаще всего скрыты от глаз; однако они могут быть расширены или настроены по необходимости. К счастью, в большинстве случаев настройки по умолчанию вполне подходят.
Применение файла *.config серверной или клиентской стороны технически не обязательно. Можно жестко закодировать хост и клиента, указав необходимые детали. Очевидная проблема такого подхода состоит в том, что если придется менять настройку, то нужно будет внести изменения в код, перекомпилировать и заново развернуть множество сборок. Использование файла *.config делает кодовую базу намного более гибкой, поскольку все изменения настроек производятся редактированием конфигурационных файлов и последующим перезапуском.
4.2 Основные понятия WCF
Хосты и клиенты взаимодействуют друг с другом, согласовывая так называемые ABC — условное наименование для запоминания основных блоков приложения WCF, специфицирующих адрес, привязку и контракт (address, binding, contract — ABC).
• Адрес. Местоположение сервиса. В коде представлен типом System. Uri, однако значение обычно хранится в файлах *.config.
• Привязка. WCF поставляется с множеством различных привязок, специфицирующих сетевые протоколы, механизмы кодирования и транспортный уровень.
• Контракт. Описание каждого метода, представленного сервисом WCF.
Однако разработчик не обязан определять сначала адрес, за ним привязку и только потом — контракт. Во многих случаях разработчик WCF начинает с определения контракта сервиса, за которым следует адрес и привязки (любой порядок допустим, если только все аспекты указаны).
Понятие контракта является ключевым при построении сервиса WCF. Хотя это и не обязательно, подавляющее большинство приложений WCF будут начинаться с определения типов интерфейсов .NET, используемых для представления набора элементов, которые поддерживаются данным типом WCF. В частности, интерфейсы, которые представляют контракт WCF, называются контрактами сервиса (service contract). Классы (или структуры), реализующие их, носят название типов сервисов (service type).
Контракты сервисов WCF оснащаются различными атрибутами, наиболее часто используемые из которых определены в пространстве имен System. ServiceModel. Когда элементы контракта содержат только простые типы данных, можно строить полную службу WCF, не используя ничего помимо атрибутов [ServiceContract] и [OperationContract].
Однако если элементы представляют специальные типы, придется обратиться к пространству имен *****ntime. Serialization. Здесь расположены дополнительные атрибуты (например, [DataMember] и [DataContract]) для тонкой настройки процесса определения интерфейсных типов.
Мы, конечно, не обязаны использовать интерфейсы CLR для определения контракта WCF. Многие из этих атрибутов могут применяться к открытым элементам открытого класса или структуры. Однако, учитывая множество преимуществ программирования на основе интерфейсов (полиморфизм, поддержка множества версий и т. п.), лучше считать хорошим тоном использование интерфейсов при определении контрактов WCF.
Как только контракт (или набор контрактов) определен и реализован внутри библиотеки службы, следующий логический шаг состоит в построении агента хостинга для самой службы WCF. Как уже упоминалось, на выбор доступно множество возможных вариантов хостов, и все они специфицируют привязки, используемые удаленными клиентами для получения доступа к функциональности типа службы.
Выбор из набора привязок — это область, которая отличает разработку WCF от .NET Remoting и/или разработки веб-сервисов XML, поскольку WCF поставляется с множеством возможных привязок на выбор, каждая из которых ориентирована на определенные потребности. Если ни одна из готовых привязок не удовлетворяет, можно создать свою реализацию, расширив тип CustomBinding.
Привязка WCF может специфицировать следующие характеристики:
• контракт, реализуемый сервисом;
• транспортный слой, используемый для передачи данных (HTTP, MSMQ, именованные конвейеры, TCP);
• каналы, используемые транспортом (однонаправленные, запрос-ответ, дуплексные);
• механизм кодирования, используемый для работы с данными (XML, двоичный и т. п.);
• любые поддерживаемые протоколы веб-сервисов (если допускаются привязкой), такие как WS-Security, WS-Transactions, WS-Reliability и т. д.
Опции BasicHttpBinding, WSHttpBinding, WSDualHttpBinding и WSFederationHttpBinding предназначены для представления контрактных типов через протоколы веб-сервисов XML.
При построении распределенного приложения, включающего машины, которые сконфигурированы с библиотеками .NET 4.0, можно получить выигрыш в производительности, минуя привязки веб-сервисов и работая непосредственно с TCP, что гарантирует кодирование данных в компактном двоичном формате вместо XML. При использовании привязок NetNamedPipeBinding, NetPeerTcpBinding, NetTcpBinding и клиент, и хост должны быть приложениями .NET.
И, наконец, если мы пытаемся интегрироваться с сервером MSMQ, то непосредственный интерес представляют NetMsmqBinding и MsmqlntegrationBinding.
Как только контракты и привязки установлены, нужно указать адреса для сервиса WCF. Это очевидно важно, поскольку удаленные клиенты не смогут взаимодействовать с удаленными типами, если не смогут найти их.
Подобно большинству аспектов WCF, адрес может быть жестко закодирован в сборке через тип System. Uri или вынесен в файл *.config.
В любом случае точный формат адреса WCF отличается в зависимости от выбранной привязки (на основе HTTP, именованных каналов, TCP или MSMQ). На самом высоком уровне адреса WCF могут специфицировать перечисленные ниже единицы информации:
• Scheme. Транспортный протокол (HTTP и т. п.).
• MachineName. Полностью квалифицированное доменное имя машины.
• Port. Во многих случаях не обязательный параметр. Например, привязка HTTP по умолчанию использует порт 80.
• Path. Путь к сервису.
Эта информация может быть представлена следующим обобщенным шаблоном (значение Port необязательно, поскольку некоторые привязки его не используют):
scheme://<MachineName>[:Port]/Path
При использовании привязки на базе веб-сервиса адрес разбивается следующим образом:
http://localhost:8080/MyWCFService.
Хотя единственный сервис WCF представляет только один адрес (на основе одной привязки), можно сконфигурировать коллекцию уникальных адресов (с разными привязками). Это делается внутри файла *.сonfig определением множества элементов <endpoint>. Здесь можно специфицировать любое количество ABC для одного и того же сервиса. Такой подход полезен, когда необходимо позволить клиентам выбирать протокол, которые они хотят использовать для коммуникации с сервисом.
4.3 Авторизация и способы ее реализации
Когда мы читаем литературу по безопасности для веб-сервисов, то мы обычно находим набор фундаментальных принципов, которые применимы к любой распределенной системе. Далее рассматриваются некоторые из них.
Аутентификация клиента — это процесс уникальной идентификации стороны, которая работает источником сообщения для наших приложений или сервисов. Эта сторона также называется отправителем сообщений или клиентом сервиса.
В общем, процесс аутентификации должен ответить на два вопроса: «Кто вы?» и «Как вы это докажете?».
Для ответа на первый вопрос отправитель должен предоставить некоторые доказательства, чтобы подтвердить свою идентичность. Она может принимать формы нематериальных полномочий, такие как пара из имени пользователя и его пароля, билет Kerberos, маркер с криптографической информацией или что-то более материальное, например, сертификат X509.
С другой стороны, сервис должен иметь механизм, чтобы удостовериться, что представленное доказательство является законным, и может ли он доверять этому доказательству или нет. Отправитель успешно аутентифицирован, только если доказательство аутентичности было выполнено успешно.
Аутентификация клиента — это не единственный сценарий. Есть еще ряд случаев, когда отправителю нужно удостовериться в идентичности сервиса. Этот тип известен под названием Аутентификации сервиса, он представляет собой проверенную практику предотвращения фишинговых атак.
Фишинг в данном контексте представляет общую угрозу безопасности, где кто-то (злоумышленник), публикует поддельный сервис с той же сигнатурой, что и оригинал, чтобы захватить важные или конфиденциальные данные о пользователе.
Взаимная проверка подлинности – это когда и клиент, и сервис проверяют подлинность друг друга до завершения любой операции.
Давайте предположим, что магазин, продающий товары в интернете, предоставляет сервис для сторонних приложений. Они могут покупать продукцию напрямую, не обращаясь к пользователям сайта. Этот сервис получает конфиденциальную информацию пользователей, например, кредитные карты и номера банковских счетов. Как сторонний интегратор, мы должны проверить подлинность сервера, прежде чем доверять ему секретную информацию о пользователе. Как разработчики такого сервиса, мы должны проверить подлинность пользователя, чтобы ассоциировать информацию о сделанной покупке с его профилем. Как видно, это типичный сценарий требует взаимной аутентификации.
Авторизация — это процесс, который определяет, какие системные ресурсы и операции могут быть доступны аутентифицированным пользователям. Он указывает на действия, которые пользователю разрешается выполнять. Решения по авторизации главным образом основаны на доказательствах, представленных в идентификационных данных аутентифицируемого пользователя, таких как пользовательские заявки или некоторые другие свидетельства, представленные сторонним приложением.
Возвращаясь к нашему примеру из аутентификации, веб-сайт мог бы решить предоставить различные полномочия разным пользователям, использующим сервис, базируясь на определенном ключе или атрибуте, предоставленным сторонним приложением.
Целостность сообщения гарантирует, что данные в сообщении защищены от преднамеренных или случайных модификаций. Другими словами это гарантирует, что в данные, полученные службой, по пути не вмешались или изменили.
Целостность для транзитных данных обычно основана на криптографических методах, таких как цифровые подписи, хеширование, коды аутентификации сообщений. Целостность чрезвычайно полезна для предотвращения атак типа «человек посередине», когда кто-то преднамеренно запускает сниффинг сетевых пакетов или изменяет некоторых из них прежде, чем сообщение достигнет службы.
Конфиденциальность сообщения — процесс удостоверения, что данные в сообщениях остаются закрытыми и конфиденциальными, и что это не может быть прочитано несанкционированными сторонами. Как с целостностью сообщения, конфиденциальность основывается на криптографических методах, таких как шифрование данных. Для этого могут использоваться различные алгоритмы, но самые безопасные основаны на асимметричных ключах, таких как RSA. Атак «Человек по середине» или «Прослушка» можно также избежать благодаря шифрованию данных.
Две модели безопасности традиционно использовались для защиты передаваемой информации между клиентскими приложениями и веб-сервисами — транспортная и сообщений.
Обе модели безопасности обеспечивают некоторые из аспектов или принципов, которые были упомянуты выше, но делают это по-разному. Безопасность в этом контексте очень важна, и это, главным образом, касается обеспечения аутентификации и гарантии целостности и конфиденциальности сообщений службы, поскольку они передаются по сети.
Знание различий между моделями поможет выбрать одну модель согласно требованиям, которые мы предъявляем, чтобы реализовать правильную схему безопасности для своих веб-сервисов.
Транспортная безопасность направлена на улучшение возможностей безопасности, которые обеспечивают различные транспорты, чтобы защитить непрерывную передачу между отправителем сообщения или клиентским приложением и конечным веб-сервисом. Поскольку в начальной спецификации SOAP не было предусмотрено никаких схем безопасности, поэтому транспортная безопасность была лучшим дополнением для защиты связи.
В транспортной безопасности все доступные механизмы аутентификации связаны с транспортной реализацией. Значит, это представляет собой наибольшее препятствие для создания новых видов учетных данных или расширения уже существующих.
То же самое происходит при управлении защитой сообщений; каждый транспорт обеспечивает ограниченное количество встроенных опций. Наиболее распространенная опция для защиты сообщений основана на комбинации TLS (Transport Layer Security) и SSL (Secure Socket Layer), которые используются для шифрования и подписывания содержимого, отправленного «по проводу». Общее ограничение SSL/TLS — это то, что они обеспечивают безопасность только типа «точка-точка» между двумя конечными точками — клиентом и сервером. Если сообщение должно быть отправлено через различных посредников, они должны перенаправлять сообщение по новому соединению SSL. Кроме того, после того, как сообщения оставляют транспорт, они перестают быть безопасными.
Большое преимущество транспортной модели в сравнении с моделью сообщений состоит в том, что участвующим сторонам совершенно нет нужды понимать WS-Security, которая в некоторых случаях представляет собой большое препятствие для достижения функциональной совместимости протокола между различными платформами или стеками веб-сервисов. Это препятствие обусловлено двумя основными факторам:
- Сложность спецификации WS-Security. Различия в финальных реализациях разных поставщиков веб-сервисов.

При использовании модели сообщения все метаданные безопасности, такие как цифровые подписи, зашифрованные элементы, удостоверения пользователя, и криптографические ключи являются автономными в пределах сообщения SOAP. Эта модель безопасности основана на спецификации WS-Security, которая главным образом описывает, как подписать или зашифровать части SOAP-пакета, используя различные алгоритмы или даже различные ключи.
Как и реализация XML, WS-Security представляет очень гибкое решение для поддержки различных виды учетных данных или создания новых. Учетные данные и ключи представлены в этой спецификации как маркеры безопасности, универсальные конструкции XML, которые инкапсулируют определенную информацию о них. Кроме того, различные маркеры безопасности уже произошли из существующих технологий безопасности, таких как Kerberos, сертификаты X509, пары имена пользователей/пароли, и описываются в сопутствующих спецификациях, называемых маркерными профилями.
Основное отличие от транспортной модели – это то, что сообщения могут быть переданы другим сервисам или посредническим системам без нарушения безопасности, она всегда присутствует, независимо от того, оставляют ли сообщения транспорт или нет.
Важнейшим местом для конфигурирования параметров безопасности являются привязки. Как и многое другое в .NET, это можно сделать программно либо через файл *.config.
Во избежание плохих практик конфигурирования безопасности, команда WCF ограничивает число настроек безопасности, которые могут использоваться в разделе конфигурации. Имя пользователя и пароля учетной записи являются примером этого. Это было бы не слишком хорошо жестко кодировать пароли в конфигурационном файле, и по этой причине, они доступны только в программной модели конфигурации.

Более того, для упрощения процесса конфигурации, все привязки идут с предопределенными схемами конфигурации, которые удовлетворяют наиболее распространенным сценариям использования. Таким образом, если мы не укажем определенные настройки, WCF попытается использовать схему безопасности по умолчанию.
Единственное, что объединяет все эти подходы — это то, что каждый из них требует, чтобы данный пользователь находился в сеансе, а веб-приложение было загружено в память. Как только пользователь выходит (или отключается по тайм-ауту) из сайта (или веб-сайт останавливается), сайт опять становится не поддерживающим состояние.
Рассмотрим следующую конфигурацию, которую поддерживает WsHttpBinding.
< wsHttpBinding >
< binding name=”UsernameBinding” >
< security mode=”Message” >
< message clientCredentialType=”UserName”/ >
< /security >
< /binding >
< /wsHttpBinding >
Здесь сервис настроен на модель безопасности сообщений и использование маркера профиля с именем и паролем. Остальные настройки будут сделаны по умолчанию.
Настройка режима безопасности определяет два фундаментальных аспекта для любого сервиса: модель безопасности для защиты сообщений и поддерживаемая схема аутентификации клиента. У каждого режима есть свой механизм отправки учетных данных аутентификации на сторону сервиса, и поэтому некоторые опции аутентификации не могут быть доступными согласно выбранной модели обеспечения безопасности.
В частности, «федеративная аутентификация» поддерживается только с аутентификацией сообщений. Если мы вынуждены поддерживать эту схему безопасности, то модель сообщений — это единственная опция, которую мы имеем. Эта установка доступна в модели конфигурации через свойство Mode в элементе безопасности.
Следующий пример показывает, как сконфигурировать режим для WsHttpBinding с использованием конфигурационного файла, и эквивалент в программном коде.
< wsHttpBinding >
< binding name=”helloWorld” >
< security mode=”TransportWithMessageCredential” > < /security >
< /binding >
< /wsHttpBinding >
WSHttpBinding binding = new WSHttpBinding();
binding. Security. Mode = SecurityMode. TransportWithMessageCredential;
Возможные варианты: None, Transport, Message, Both, TransportWithMessageCredentials, TransportCredentialOnly.
По умолчанию WCF шифрует и подписывает все сообщения «на проводе», чтобы обеспечить конфиденциальность данных и их целостность. В некоторых обстоятельствах, если передаваемое сообщение не содержит уязвимой информации, мы можем вообще выключить шифрование и подписать сообщение, чтобы сохранить целостность данных, не беспокоясь по поводу конфиденциальности. Для таких сценариев WCF обеспечивает гибкость изменения уровня защиты по умолчанию, когда используется режим Message.Security.
Уровень защиты может быть сконфигурирован или в уровне сервиса при определении контракта или на уровне операции для более тонкой настройки. Когда уровень защиты определен на обоих уровнях, уровень защиты в операции перегружает существующее определение на уровне сервиса.
Контракты сообщений также поддерживают способ переопределения уровня защиты для операции. Атрибут [ProtectionLevel] может быть определен непосредственно в контракте сообщения или в любом заголовке сообщения или теле.
Поддерживаемые значения для этого атрибута: None, Sign, EncryptAndSign. Значение None отключает защиту, Sign обеспечивает только целостность, а последнее значение предназначено для обеспечения конфиденциальности и целостности сообщения.
Уровень защиты настраивается только в *.config. Следующий пример иллюстрирует, как эта настройка изменяет разные уровни (операции или сообщения) в определении службы.
[MessageContract(ProtectionLevel = ProtectionLevel. None)]
public class HelloWorldRequestMessage
{
[MessageHeader]
public string SampleHeader { get; set; }
[MessageBodyMember()]
public string Message { get; set; }
}
[MessageContract]
public class HelloWorldResponseMessage
{
public string ResponseMessage { get; set; }
}
[ServiceContract(ProtectionLevel = ProtectionLevel. EncryptAndSign)]
public interface IHelloWorld
{
[OperationContract(ProtectionLevel = ProtectionLevel. Sign)]
HelloWorldResponseMessage Hello(HelloWorldRequestMessage request);
}
Последний результат, показанный в данном коде — это то, что сообщение-запрос не будет защищено, а ответное сообщение будет защищено на уровне операции, которая будет только подписана.
Тип клиентских учетных данных — очень важная установка, которая определяет схему аутентификации, используемую службой. Это представляет тип учетных данных, ожидаемых для аутентификации клиентского или потребительского приложение.
Поддерживаемые опции для этой установки изменятся согласно выбранному режиму безопасности и транспорту. Хотя доступные параметры для безопасности сообщения в наиболее распространенных привязках в значительной степени похожи — None, Windows, Username, Sertificate и IssueToken — опции для транспортной модели, и ограничены поддерживаемыми схемами аутентификации в транспортном уровне как таковом.
Пример использования типов клиентских учетных данных в моделях транспорта и сообщений:
< wsHttpBinding >
< binding name=”helloWorld” >
< security mode=”Transport” >
< transport clientCredentialType=”Windows”/ >
< message clientCredentialType=”Windows”/ >
< /security >
< /binding >
< /wsHttpBinding >
Здесь WCF будет использовать определение учетных данных клиент согласно транспортной модели, т. к. режим безопасности был установлен в Transport. Аналогичный элемент из раздела message будет просто игнорироваться.
Конфигурирование в коде будет очень похожим на то, как мы это сделали в файле *.config.
WSHttpBinding binding = new WSHttpBinding();
binding. Security. Mode = SecurityMode. Transport;
binding. Security. Transport. ClientCredentialType = HttpClientCredentialType. Windows;
binding. Security. Message. ClientCredentialType = MessageCredentialType. Windows;
За более подробной информацией о настройке параметров аутентификации рекомендуется обратиться к соответствующей литературе. Мы же перейдем к не менее интересному аспекту безопасности — процессу авторизации.
WCF обеспечивает два механизма авторизации в сервисах. Во-первых, простая и удобная в работе схема, основанная на пользовательских ролях. Во-вторых, более сложная и мощная схема, основанная на требованиях. Мы обсудим обе схемы, и как они могут использоваться для реализации устойчивой авторизации.
Авторизация, основанная на ролях — это не велосипед, изобретенный разработчиками WCF. Он существовал с самого начала в платформе .NET. Основная идея — ассоциировать список ролей с пользователем, и потом во время выполнения реализация сервиса может позволить этому списку принять решения относительно авторизации. Приложения может получить список ролей, ассоциированных с пользователем из различных источников (базы данных, рабочие группы/домены Windows и другие).
В мире .NET идентичность пользователя и роли, связанные с этой идентичностью в определенном контексте, представляются интерфейсами System.Security.Principal.IIdentity и System.Security.Principal.IPrincipal.
Первый из них — это класс, предоставляющий информацию об имени пользователя (Name), аутентифицирован ли он (IsAuthenticated), и как он был аутентифицирован (AuthenticationType).
public interface IIdentity
{
string AuthenticationType { get; }
bool IsAuthenticated { get; }
string Name { get; }
}
С другой стороны, System. Security.Principal.IPrincipal содержит ссылку на Identity пользователя (типа IIdentity), и обеспечивает метод верификации того, был ли пользователь ассоциирован с определенной ролью:
public interface IPrincipal
{
bool IsInRole(string role);
IIdentity Identity { get; }
}
Некоторые реализации находятся вне поля зрения .NET. Например, мы можем обнаружить реализации System. Secutity. Principal. WindowsIdentity и System. Security. Principal. WindowsPrincipal для представления пользователя Windows, или более универсальную реализацию в классах System. Security. Principal. GenericIdentity и System. Security. Principal. GenericPrincipal.
Принцип безопасности обычно присоединен к выполняющемуся в текущий момент потоку нашего приложения. В этом можно убедиться через статическое свойство CurrentPrincipal класса System.Threading.Thread. Одна часть приложения отвечает за инициализацию этого свойства, тогда другая часть приложения может получить его и использовать для выполнения любого кода авторизации.
WCF работает аналогично: элемент <serviceAuthorization> управляет созданием экземпляра System. Security. IPrincipal и ассоциирует его с потоком, обрабатывающим текущий запрос.
Когда клиенты аутентифицируются операционной системой, WCF старается населить Thread.CurrentPrincipal значением WindowsPrincipal. Для других типов аутентификации у нас есть выбор между получением ролей от поставщика в рамках и разработкой собственной политики авторизации (GenericPrincipal в большинстве случаев).
В дополнение к методу IsInRole, доступному в пользовательском принципале для выполнения проверок безопасности, основанной на ролях, имеется также атрибут PermissionAttribute, который позволяет аннотировать операции сервиса требованиями к роли. Когда этот атрибут установлен, подсистема CLR проверяет, отвечает ли принципал, присоединенный к текущему потоку, требованиям, указанным в атрибуте. Если нет, то будет выброшено исключение SecurityException. WCF перехватит его и преобразует в ошибку AccessDenied перед тем, как вернуть ответ клиенту.
Следующий псевдокод показывает, как использовать этот атрибут, а также метод IsInRole.
public class Service : IService
{
[PrincipalPermission(SecurityAction. Demand, Role = "Administrators")]
public string DoOperation()
{
return...;
}
}
public class Service : IService
{
public string DoOperation()
{
if (Thread. CurrentPrincipal. IsInRole("Administrators"))
{
return...
}
else
{
throw new SecurityException();
}
}
}
Как видно, использование атрибута требует, чтобы мы жестко закодировали имена групп еще во время проектирования операции сервиса.
WCF передает заявки, связанные с аутентифицируемыми учетными данными, и заявки, создаваемые в пользовательских политиках авторизации, как часть контекста защиты операции.
Поэтому мы можем использовать всю гибкость, которую обеспечивают заявки, чтобы представить идентификационных данных или индивидуальные права для реализации кода авторизации в операциях службы. Все наборы заявок, которые были сгенерированы до выполнения операции, доступны в WCF через контекст авторизации.
WCF обеспечивает доступ к контексту авторизации через поток — статический ServiceSecurityContext, который представляет собой контейнер для наборов заявок, политик авторизации и текущих пользовательских идентификационных данных:
public class ServiceSecurityContext
{
public AuthorizationContext AuthorizationContext { get; }
public ReadOnlyCollection < IAuthorizationPolicy > AuthorizationPolicies { get; }
public static ServiceSecurityContext Current { get; }
public bool IsAnonymous { get; }
public IIdentity PrimaryIdentity { get; }
public WindowsIdentity WindowsIdentity { get; }
}
Операция может просто перечислить наборы заявок, полученные как часть контекста авторизации, чтобы проверить, есть ли у пользователя полномочия на выполнение тех или иных действий.
public class Service : IService
{
public void DoAction()
{
bool isFound = false;
foreach (ClaimSet cs in OperationContext. Current. ServiceSecurityContext
.AuthorizationContext. ClaimSets
)
{
foreach (Claim claim in cs. FindClaims("urn:Group",
Rights. PossessProperty))
{
if (claim. Resource. ToString().Equals("administrator",
StringComparison. InvariantCultureIgnoreCase))
{
isFound = true;
break;
}
}
}
if (!isFound)
{
throw new SecurityException("You are not authorized");
}
}
}
Здесь операция выглядит как специфичная заявка “urn:Group” для значения свойства Resource установленного в “administrator”. Если такое не было найдено, то бросается исключение, говорящее о том, что пользователь не имеет полномочий на выполнение данной операции.
Важно: как мы могли видеть, сравнительно легко использовать роли или заявки для реализации логики авторизации. Тем не менее, в некоторых случаях мы можем централизовать ее в одном месте и использовать для каждого входящего запроса без «размазывания» его на все сервисные операции.
Для этой цели WCF приберег специальную точку расширения известную как Менеджер авторизации. Это класс, являющийся наследником System. ServiceModel. ServiceAuthorizationManager со своей реализацией защищенного метода CheckAccessCore, который, собственно говоря, и содержит код кастомизированной авторизации для каждого запроса.
Подробнее см. в соответствующей литературе.
Использованные источники
1. Cibraro, P. Professional WCF 4: Windows Communication Foundation 4. / P. Cibraro etc. Wiley Publishing, 2010. — 476 p.
2. patterns & practices: WCF Security Guidance — http://wcfsecurity. /
3. WCF структуры Службы разрешения — http://ru. /index. php? db=so&id=145025
4. Windows Communication Foundation is... – http://msdn. /en-us/netframework/aa663324.aspx
5. Авторизация — http://msdn. /ru-ru/library/ms733071.aspx
6. Заметки о безопасности: Обзор удостоверений на основе заявок. – http://msdn. /ru-ru/magazine/cc163366.aspx
7. Макки, А. Введение в NET 4.0 и Visual Studio 2010 для профессионалов. / А. Макки. - М.: "", 2010. — 416 с.
8. Троелсен, Э. Язык программирования С# 2008 и платформа. NET 3.5, 4-е изд. / Э. Троелсен. — М.: "", 2010. — 1344 с.




