WCF, поставщик членства ASP.NET и служба аутентификации - PullRequest
13 голосов
/ 11 сентября 2008

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

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

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

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

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

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

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

Ответы [ 6 ]

5 голосов
/ 12 сентября 2008

Я наконец нашел способ заставить эту работу. Для аутентификации я использую " WCF Authentication Service ". При аутентификации сервис попытается установить куки аутентификации. Мне нужно извлечь этот файл 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 и извлекает куки-файл аутентификации из ответа. Второй блок добавит заголовок к запросу перед вызовом метода сервиса «GetDives».

Меня совсем не устраивает этот код, и я думаю, что лучшей альтернативой может быть использование "Web Reference" вместо "Service Reference" и использование вместо этого стека .NET 2.0.

2 голосов
/ 12 сентября 2008

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

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

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

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

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

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

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

1 голос
/ 09 июля 2009

На клиенте измените тег для службы (внутри ), включив в него: allowCookies = "true"

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

0 голосов
/ 12 мая 2009

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

0 голосов
/ 16 января 2009

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

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

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

0 голосов
/ 15 сентября 2008

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

Я постараюсь потом что-нибудь высмеять и отправлю вам.

- larsw

...