WCF, поставщик членства ASP.NET и служба аутентификации

StackOverflow https://stackoverflow.com/questions/56112

  •  09-06-2019
  •  | 
  •  

Вопрос

Я написал приложение Silverlight 2, взаимодействующее со службой WCF (BasicHttpBinding).Сайт, на котором размещено содержимое Silverlight, защищен с помощью поставщика членства ASP.NET.Я могу получить доступ к текущему пользователю, используя HttpContext.Current.User.Identity.Name из моей службы WCF, и я включил AspNetCompatibilityRequirementsMode.

Теперь я хочу написать приложение для Windows, использующее тот же веб-сервис.Для обработки аутентификации я включил Служба аутентификации, и могу вызвать «вход» для аутентификации моего пользователя...Окей, все хорошо...Но как, черт возьми, мне установить этот файл cookie аутентификации на другом моем сервисном клиенте?!

Обе службы размещены в одном домене.

  • MyDataService.svc <- тот, который работает с моими данными
  • AuthenticationService.svc <- тот, который приложение Windows должно вызывать для аутентификации.

Я не хочу создавать новую службу для клиента Windows или использовать другую привязку...

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

По словам коллег, решение заключается в добавлении конечной точки wsHttpBinding, но я надеюсь, что смогу это обойти...

Это было полезно?

Решение

Наконец я нашел способ заставить эту работу работать.Для аутентификации я использую "Служба аутентификации WCF".При аутентификации служба попытается установить файл cookie аутентификации.Мне нужно извлечь этот файл cookie из ответа и добавить его к любому другому запросу, отправленному другим веб-сервисам на том же компьютере.Код для этого выглядит следующим образом:

var authService = new AuthService.AuthenticationServiceClient();
var diveService = new DiveLogService.DiveLogServiceClient();

string cookieHeader = "";
using (OperationContextScope scope = new OperationContextScope(authService.InnerChannel))
{
    HttpRequestMessageProperty requestProperty = new HttpRequestMessageProperty();
    OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = requestProperty;
    bool isGood = authService.Login("jonas", "jonas", string.Empty, true);
    MessageProperties properties = OperationContext.Current.IncomingMessageProperties;
    HttpResponseMessageProperty responseProperty = (HttpResponseMessageProperty)properties[HttpResponseMessageProperty.Name];
    cookieHeader = responseProperty.Headers[HttpResponseHeader.SetCookie];                
}

using (OperationContextScope scope = new OperationContextScope(diveService.InnerChannel))
{
    HttpRequestMessageProperty httpRequest = new HttpRequestMessageProperty();
    OperationContext.Current.OutgoingMessageProperties.Add(HttpRequestMessageProperty.Name, httpRequest);
    httpRequest.Headers.Add(HttpRequestHeader.Cookie, cookieHeader);
    var res = diveService.GetDives();
}      

Как видите, у меня есть два клиента службы: один для службы аутентификации, а другой для службы, которую я собираюсь использовать.Первый блок вызывает метод Login и извлекает из ответа файл cookie аутентификации.Второй блок добавит заголовок к запросу перед вызовом метода сервиса GetDives.

Меня этот код совершенно не устраивает, и я думаю, что лучшей альтернативой было бы использовать «Веб-ссылку» вместо «Ссылки на службы» и вместо этого использовать стек .NET 2.0.

Другие советы

Веб-службы, например созданные WCF, часто лучше всего использовать без сохранения состояния, поэтому каждый вызов веб-службы начинается заново.Это упрощает код сервера, поскольку нет необходимости иметь «сеанс», который вызывает состояние клиента.Это также упрощает клиентский код, поскольку нет необходимости хранить билеты, файлы cookie или другие штуки, которые предполагают что-то о состоянии сервера.

Создание двух сервисов описанным способом обеспечивает сохранение состояния.Клиент либо «аутентифицирован», либо «не аутентифицирован», и MyDataService.svc должен выяснить, какой именно.

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

Подробности см. в статье MSDN. здесь.

[Что меня в этом очень привлекает, поскольку я ленив, так это то, что это полностью декларативно.Я просто разбрасываю нужные записи конфигурации для своего MembershipProvider в app.config приложения и!бинго!все вызовы каждого контракта в службе аутентифицируются.]

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

Одно дело, что это не делает Give — это возможность предоставить возможность «входа в систему».Для этого вы можете либо предоставить сервисный контракт (с проверкой подлинности!), который ничего не делает (кроме как выдает ошибку в случае сбоя аутентификации), либо вы можете использовать службу поставщика членства, как описано в исходной статье, на которую есть ссылка.

На клиенте измените тег <binding> для службы (внутри <system.serviceModel>), включив в него:разрешитьCookies="истина"

Теперь приложение должно сохранить файл cookie и использовать его.Вы заметите, что IsLoggedIn теперь возвращает true после входа в систему — он возвращает false, если вы не разрешаете использование файлов cookie.

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

Позже постараюсь что-нибудь помакетировать и пришлю вам.

--larsw

Вам следует взглянуть на CookieContainer объект в System.Net.Этот объект позволяет клиенту, не являющемуся браузером, сохранять файлы cookie.Это то, что моя команда использовала в последний раз, когда столкнулась с этой проблемой.

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

Мы пошли по пути без сохранения состояния для нашего текущего набора служб WCF и приложения Silverlight 2.Silverlight 2 можно заставить работать со службами, связанными с безопасностью TransportWithMessageCredential, хотя для этого требуется специальный код безопасности на стороне Silverlight.В результате любое приложение может получить доступ к службам, просто указав имя пользователя и пароль в заголовках сообщений.Это можно сделать один раз в пользовательской реализации IRequestChannel, чтобы разработчикам не приходилось беспокоиться о самостоятельной установке значений.Хотя у WCF есть простой способ сделать это для разработчиков: я считаю, что это serviceProxy.Security.Username и serviceProxy.Security.Password или что-то столь же простое.

Я написал это некоторое время назад, когда использовал службы клиентских приложений для аутентификации в веб-сервисах.Он использует инспектор сообщений для вставки заголовка cookie.Есть текстовый файл с документацией и демо-проектом.Хотя это не совсем то, что вы делаете, это довольно близко.Вы можете скачать его с здесь.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top