Как передать учетные данные пользователя из WebClient в службу REST WCF? - PullRequest
8 голосов
/ 28 апреля 2009

Я пытаюсь открыть службу WCT REST, и только пользователи с действительными именем пользователя и паролем смогут получить к ней доступ. Имя пользователя и пароль хранятся в базе данных SQL.

Вот договор на обслуживание:

public interface IDataService
{
    [OperationContract]
    [WebGet(ResponseFormat = WebMessageFormat.Json)]
    byte[] GetData(double startTime, double endTime);
}

Вот конфигурация WCF:

<bindings>
  <webHttpBinding>
    <binding name="SecureBinding">
      <security mode="Transport">
        <transport clientCredentialType="Basic"/>
      </security>
    </binding>
  </webHttpBinding>
</bindings>
<behaviors>
  <serviceBehaviors>
    <behavior name="DataServiceBehavior">
      <serviceMetadata httpGetEnabled="true"/>
      <serviceCredentials>
        <userNameAuthentication
           userNamePasswordValidationMode="Custom"
           customUserNamePasswordValidatorType=
                 "CustomValidator, WCFHost" />
      </serviceCredentials>
    </behavior>
  </serviceBehaviors>
</behaviors>
<services>
  <service behaviorConfiguration="DataServiceBehavior" name="DataService">
    <endpoint address="" binding="webHttpBinding"
              bindingConfiguration="SecureBinding" contract="IDataService" />
  </service>
</services>

Я получаю доступ к службе через класс WebClient в приложении Silverlight. Однако я не смог выяснить, как передать учетные данные пользователя в службу. Я пробовал различные значения для client.Credentials, но, похоже, ни одно из них не вызывает код в моем пользовательском валидаторе. Я получаю следующую ошибку: Основное соединение было закрыто: при отправке произошла непредвиденная ошибка.

Вот пример кода, который я пробовал:

   WebClient client = new WebClient();
   client.Credentials = new NetworkCredential("name", "password", "domain");
   client.OpenReadCompleted += new OpenReadCompletedEventHandler(GetData);
   client.OpenReadAsync(new Uri(uriString));

Если я установлю режим безопасности на Нет, все будет работать. Я также пробовал другие значения clientCredentialType, и ни одно из них не работало. Я также самостоятельно разместил службу WCF, чтобы устранить проблемы, связанные с попытками IIS аутентифицировать пользователя до того, как служба получит шанс.

Будем весьма благодарны за любые комментарии относительно возможных проблем. Спасибо.

Обновление : Благодаря превосходным предложениям Мехмета. Вот конфигурация трассировки, которая была у меня:

 <system.diagnostics>
    <sources>
      <source name="System.ServiceModel"
              switchValue="Information, ActivityTracing"
              propagateActivity="true">
        <listeners>
          <add name="xml" />
        </listeners>
      </source>
      <source name="System.IdentityModel" switchValue="Information, 
               ActivityTracing" propagateActivity="true">
        <listeners>
          <add name="xml" />
        </listeners>
      </source>
    </sources>
    <sharedListeners>
      <add name="xml"
           type="System.Diagnostics.XmlWriterTraceListener"
           initializeData="c:\Traces.svclog" />
    </sharedListeners>
  </system.diagnostics>

Но я не увидел ни одного сообщения от моего клиента Silverlight. Что касается https против http, я использовал https следующим образом:

string baseAddress = "https://localhost:6600/";
_webServiceHost = new WebServiceHost(typeof(DataServices), 
                new Uri(baseAddress));
_webServiceHost.Open();

Однако я не настроил ни одного SSL-сертификата. Это проблема?

Ответы [ 3 ]

2 голосов
/ 03 июля 2012

Поскольку вы используете обычную аутентификацию, вам необходимо отправить имя пользователя и пароль в заголовке запроса. Пример ручного добавления учетных данных в заголовок показан ниже:

HttpWebRequest req = (HttpWebRequest)WebRequest.Create(@"https://localhost:6600/MyWCFService/GetData");
//Add a header to the request that contains the credentials
//DO NOT HARDCODE IN PRODUCTION!! Pull credentials real-time from database or other store.
string svcCredentials = Convert.ToBase64String(ASCIIEncoding.ASCII.GetBytes("userName" + ":" + "password"));
req.Headers.Add("Authorization", "Basic " + svcCredentials);
//Parse the response and do something with it...
using (WebResponse svcResponse = (HttpWebResponse)req.GetResponse())
{
  using (StreamReader sr = new StreamReader(svcResponse.GetResponseStream()))
  {
    //Sample parses json response; your code here may be different
    JavaScriptSerializer js = new JavaScriptSerializer();
    string jsonTxt = sr.ReadToEnd();
  }
}
0 голосов
/ 02 февраля 2013

То, что atconway , предложенное выше, кажется верным способом, но ваш сервис должен прочитать данные из строки base 64 из заголовка и преобразовать обратно в строку, а затем выполнить аутентификацию. Но это необходимо для проверки подлинности при каждом вызове.

Еще один подход заключается в использовании защищенного ключа. и токен

  1. У каждого клиента есть безопасный ключ , который он отправляет при первом запросе, возможно в шапке.
  2. Вы можете сгенерировать ключ как key = MD5Hash (имя пользователя + пароль);
  3. В ответ он получает токен , затем токен отправляется в каждый запрос. Токен может быть Guid. Срок действия каждого токена истек через x мин.
  4. На стороне сервера вы можете поддерживать одноэлементный словарь, такой как Dictionay, для проверки истечения токена, когда текущее время> время истечения удаляет его из словаря.
  5. Чтобы продлить сеанс, вставьте метод возобновления сеанса в свой код.

Для обеспечения внешней безопасности

Имейте пару личного / открытого ключа, клиент зашифрует все данные поста с помощью открытого ключа, а вы расшифруете с помощью личного ключа.

0 голосов
/ 28 апреля 2009

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

...