wcf данные контракты авторизация

Как пользоваться [PrincipalPermission(SecurityAction.Demand, Role = "Administrators")] атрибут на класс?

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

2 ответа

Решение

PrincipalPermission Атрибут может украшать метод или класс. Поэтому возможно ограничить доступ к экземпляру объекта. Необходимо сделать несколько вещей:

  1. Настройте выбранную службу и привязку клиента для использования безопасности. Уточнить Windows как тип учетных данных клиента.
  2. Настройте службу для использования групп Windows для авторизации.
  3. Украсьте класс, который будет содержать конфиденциальную информацию с PrincipalPermission приписывать.

Если экземпляр singleton необходимо передать ServiceHost конструктор, сделайте следующее:

  1. Создать единый экземпляр службы. Thread.CurrentPrincipal должны иметь разрешения, необходимые для доступа к конфиденциальному объекту.
  2. Создайте ServiceHost Экземпляр, передав сервисный экземпляр Singleton. Имущество InstanceContextMode из ServiceBehavior атрибут должен быть установлен в InstanceContextMode.Single,

Иначе:

  1. Создайте ServiceHost экземпляр, передав тип сервиса.

При желании, украсьте метод обслуживания FaultContract атрибут и бросок FaultException от него во избежание неисправности клиентского канала.

Вот пример:

Файл конфигурации сервиса:

<system.serviceModel>
    <services>
        <service name="Server.Service" behaviorConfiguration="Authorization">
            <endpoint address=""
                      binding="netTcpBinding" bindingConfiguration="TCP"
                      contract="Common.IService" />
            <host>
                <baseAddresses>
                    <add baseAddress="net.tcp://localhost:13031/Service"/>
                </baseAddresses>
            </host>
        </service>
    </services>
    <bindings>
        <netTcpBinding>
            <binding name="TCP" openTimeout="00:30:00" closeTimeout="00:00:10" maxReceivedMessageSize="2147483647">
                <readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647"/>
                <security mode="Message">
                    <message clientCredentialType="Windows" />
                </security>
            </binding>
        </netTcpBinding>
    </bindings>
    <behaviors>
        <serviceBehaviors>
            <behavior name="Authorization">
                <serviceAuthorization principalPermissionMode="UseWindowsGroups" />
            </behavior>
        </serviceBehaviors>
    </behaviors>
</system.serviceModel>

Файл конфигурации клиента:

<system.serviceModel>
    <client>
        <endpoint name="NetTcpBinding_IService"
                  address="net.tcp://localhost:13031/Service"
                  binding="netTcpBinding" bindingConfiguration="TCP"
                  contract="Common.IService" />
    </client>
    <bindings>
        <netTcpBinding>
            <binding name="TCP" openTimeout="00:30:00" closeTimeout="00:00:10" sendTimeout="00:30:00" receiveTimeout="00:30:00" maxReceivedMessageSize="2147483647">
                <readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647"/>
                <security mode="Message">
                    <message clientCredentialType="Windows" />
                </security>
            </binding>
        </netTcpBinding>
    </bindings>
</system.serviceModel>

Класс конфиденциальной информации:

[PrincipalPermission(SecurityAction.Demand, Role = "Administrators" ) ]
public class ContactInfo
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public ContactInfo()
    {
        FirstName = "John";
        LastName = "Doe";
    }
    public override string ToString()
    {
        return string.Format( "{0} {1}", FirstName, LastName );
    }
}

Договор на обслуживание и его реализация:

[ServiceContract]
public interface IService
{
    [OperationContract]
    [FaultContract( typeof( string ) )]
    string GetName( int id );
}

[ServiceBehavior]
// Use following if singleton instance needs to be passed to `ServiceHost` constructor
//[ServiceBehavior( InstanceContextMode = InstanceContextMode.Single )]
public class Service : IService
{
    private Dictionary<int, ContactInfo> Contacts { get; set; }
    public Service()
    {
        Contacts = new Dictionary<int, ContactInfo>();
        IPrincipal originalPrincipal = Thread.CurrentPrincipal;
        try
        {
            Thread.CurrentPrincipal = new WindowsPrincipal( WindowsIdentity.GetCurrent() );
            Contacts.Add( 1, new ContactInfo() );
        }
        finally
        {
            Thread.CurrentPrincipal = originalPrincipal;
        }
    }
    public string GetName( int id )
    {
        if ( Contacts.Count < id )
            return null;
        try
        {
            return Contacts[ id ].ToString();
        }
        catch ( Exception ex )
        {
            throw new FaultException<string>( ex.Message );
        }
    }
}

Если вы знакомы с кодированием разрешений.NET (императивным или декларативным), шаблон точно такой же. В декларативной форме атрибут PrincipalPermissionAttribute применяется к методу в классе, который реализует контракт службы:

[PrincipalPermission(SecurityAction.Demand, Role = "Updaters")]
public bool Update()
{
return true;
}

В этом примере текущий участник проверяется, чтобы определить, принадлежит ли он роли, называемой Updaters. В фактической реализации атрибута вызывается метод IsInRole на принципале.

Для обязательного определения PrincipalPermissionAttribute создается экземпляр класса PrincipalPermission. Конструктор для PrincipalPermission принимает имя пользователя и роль в качестве параметра. При создании экземпляра можно вызвать метод Demand, чтобы определить, имеет ли текущий участник необходимые разрешения. Следующий код предоставляет пример:

PrincipalPermission p = new PrincipalPermission(null, "Updaters");
p.Demand();

конфигурация должна выглядеть так:

<behaviors>
  <serviceBehaviors>
    <behavior>
      ...
      <serviceAuthorization principalPermissionMode="UseWindowsGroups" />
    </behavior>
  </serviceBehaviors>
</behaviors>

рабочий образец смотрите на: Авторизация доступа к сервисным операциям

Другие вопросы по тегам