WCF + учетные данные пользователя

Я работаю над веб-приложением Silverlight v3 и хочу защитить доступ к службе WCF, которую использую для получения своих данных. В настоящее время WCF работает нормально, но для этого не требуются учетные данные пользователя.

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

Я хотел бы указать способ указать учетные данные заранее на стороне клиента сразу после создания моего прокси-сервера службы (я использую прокси-сервер, автоматически сгенерированный из «Добавить ссылку на службу»).

При поиске решения этой проблемы я смог найти решения, похожие на мою первую идею (с использованием параметров имени пользователя и пароля). Может ли кто-нибудь указать мне правильное направление?

Спасибо!


person Charles    schedule 18.07.2009    source источник


Ответы (3)


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

Сначала нужно включить режим совместимости ASP.NET для WCF в разделе system.ServiceModel:

<system.serviceModel>  
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" /> 
</system.serviceModel>

Как только это будет сделано, для каждого метода службы, который вы хотите понять, файл cookie ASP.NET добавьте атрибут [AspNetCompatibilityRequirements] в свой класс службы.

[ServiceContract]
[AspNetCompatibilityRequirements(
    RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class ExampleService
{
}

Теперь в каждом методе вы можете получить доступ к объекту HttpContext.Current.User.Identity, чтобы узнать личность пользователя.

Если вы хотите, чтобы определенные методы вызывались только аутентифицированными пользователями, вы можете использовать PrincipalPermission, таким образом

[OperationContract]
[PrincipalPermission(SecurityAction.Demand, Authenticated=true)]
public string Echo()

В качестве бонуса, если вы используете поставщика ролей ASP.NET, они также будут заполнены, и затем вы можете использовать PrincipalPermission для методов, чтобы ограничить их членами определенной роли:

[OperationContract]
[PrincipalPermission(SecurityAction.Demand, Role="Administators")]
public string NukeTheSiteFromOrbit()

Очевидно, это работает и в Silverlight2.

person blowdart    schedule 18.07.2009
comment
Выглядит неплохо; Вы случайно не знаете, можно ли использовать это (или что-то подобное) при использовании необработанного httpwebrequest? У меня есть собственный стек RPC, который я хотел бы защитить таким же образом (конечно, я могу задать новый вопрос, если это нетривиальный ответ) - person Marc Gravell; 18.07.2009
comment
Это должно быть да; см. silverlightshow.net/items/ - person blowdart; 18.07.2009

Не сворачивайте свои собственные и не добавляйте явные параметры - это действительно слишком много работы!

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

Ознакомьтесь с отличной статьей Мишеля Леру Бустаманте о безопасности WCF: http://www.devx.com/codemag/Article/33342

В вашем случае я бы предложил безопасность сообщений с учетными данными имени пользователя - вам нужно настроить это на обоих концах:

На стороне сервера:

<bindings>
  <basicHttpBinding>
    <binding name="SecuredBasicHttp" >
      <security mode="Message">
        <message clientCredentialType="UserName"/>
      </security>
    </binding>
  </basicHttpBinding>
</bindings>
<services>
  <service name="YourService">
    <endpoint address="http://localhost:8000/MyService"
              binding="basicHttpBinding"
              bindingConfiguration="SecuredBasicHttp"
              contract="IYourService" />
  </service>
</services>

И вам нужно применить те же настройки на стороне клиента:

<bindings>
  <basicHttpBinding>
    <binding name="SecuredBasicHttp" >
      <security mode="Message">
        <message clientCredentialType="UserName"/>
      </security>
    </binding>
  </basicHttpBinding>
</bindings>
<client>
    <endpoint address="http://localhost:8000/MyService"
              binding="basicHttpBinding"
              bindingConfiguration="SecuredBasicHttp"
              contract="IYourService" />
</client>

Теперь ваш сервер и клиент согласны с безопасностью — на клиенте вы должны указать имя пользователя и пароль для использования следующим образом:

YourServiceClient client = new YourServiceClient();

client.ClientCredentials.UserName.UserName = "your user name";
client.ClientCredentials.UserName.Password = "top$secret";

На стороне сервера вам потребуется настроить способ проверки этих учетных данных пользователя — обычно либо в отношении домена Windows (Active Directory), либо в отношении модели поставщика членства ASP.NET. В любом случае, если учетные данные пользователя не могут быть проверены для указанного вами хранилища, вызов будет отклонен.

Надеюсь, это немного поможет — безопасность — это большая тема в WCF, и у нее очень много вариантов — это может быть немного сложно, но, в конце концов, обычно это имеет смысл! :-)

Марк

person marc_s    schedule 18.07.2009
comment
Я не уверен, в каком сценарии вы смогли это сделать, но по моему опыту это не разрешено в WCF. Вы не можете использовать безопасность учетных данных пользователя в режиме сообщений в basicHttpBinding, это запрещено платформой, поскольку учетные данные будут передаваться в виде простого текста. Вы получите это InvalidOperationException: привязка BasicHttp требует, чтобы BasicHttpBinding.Security.Message.ClientCredentialType был эквивалентен типу учетных данных BasicHttpMessageCredentialType.Certificate для защищенных сообщений. Выберите безопасность Transport или TransportWithMessageCredential для учетных данных UserName. - person Grank; 11.09.2009

вы можете передать какой-либо объект аутентификации и зашифровать его на уровне сообщения с помощью WCF. Затем можно использовать аспекты C# (http://www.postsharp.org/), чтобы избежать избыточной логики. Это очень чистый способ обращения с ним.

person Steve    schedule 18.07.2009