wcf данные контракты авторизация
Как пользоваться [PrincipalPermission(SecurityAction.Demand, Role = "Administrators")]
атрибут на класс?
Я ищу способ ограничить доступ к моему объекту, т.е. если к какому-либо объекту обращаются в методе службы, и если у пользователя есть права на доступ к методу службы, но нет прав на доступ к объекту, должно быть выдано исключение.
2 ответа
PrincipalPermission
Атрибут может украшать метод или класс. Поэтому возможно ограничить доступ к экземпляру объекта. Необходимо сделать несколько вещей:
- Настройте выбранную службу и привязку клиента для использования безопасности. Уточнить
Windows
как тип учетных данных клиента. - Настройте службу для использования групп Windows для авторизации.
- Украсьте класс, который будет содержать конфиденциальную информацию с
PrincipalPermission
приписывать.
Если экземпляр singleton необходимо передать ServiceHost
конструктор, сделайте следующее:
- Создать единый экземпляр службы.
Thread.CurrentPrincipal
должны иметь разрешения, необходимые для доступа к конфиденциальному объекту. - Создайте
ServiceHost
Экземпляр, передав сервисный экземпляр Singleton. ИмуществоInstanceContextMode
изServiceBehavior
атрибут должен быть установлен вInstanceContextMode.Single
,
Иначе:
- Создайте
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>
рабочий образец смотрите на: Авторизация доступа к сервисным операциям