В основном вам нужно сделать следующее:
- Настройка безопасности на клиенте и привязке службы, чтобы удостоверение передавалось службе.
- Реализация собственного диспетчера авторизации, который будет отслеживать сеансы и позволять / запрещать пользователю использовать сервис.
- Настроить serviceAuthorization Поведение для использования реализованного менеджера авторизации.
См. Следующие примеры конфигурации и кода.
Конфигурация клиента :
<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">
<security mode="Transport">
<transport clientCredentialType="Windows" />
</security>
</binding>
</netTcpBinding>
</bindings>
</system.serviceModel>
Сервисная конфигурация :
<system.serviceModel>
<services>
<service name="Server.Service" behaviorConfiguration="customAuthorization">
<endpoint address="net.tcp://localhost:13031/Service"
binding="netTcpBinding" bindingConfiguration="TCP"
contract="Common.IService" />
</service>
</services>
<bindings>
<netTcpBinding>
<binding name="TCP">
<security mode="Transport">
<transport clientCredentialType="Windows" />
</security>
</binding>
</netTcpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="customAuthorization">
<serviceAuthorization
serviceAuthorizationManagerType="Extensions.SingleSessionPerUserManager, Extensions"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
Диспетчер пользовательских авторизаций :
public class SingleSessionPerUserManager : ServiceAuthorizationManager
{
private SessionStorage Storage { get; set; }
public SingleSessionPerUserManager()
{
Storage = new SessionStorage();
}
protected override bool CheckAccessCore( OperationContext operationContext )
{
string name = operationContext.ServiceSecurityContext.PrimaryIdentity.Name;
if ( Storage.IsActive( name ) )
return false;
Storage.Activate( operationContext.SessionId, name );
operationContext.Channel.Closed += new EventHandler( Channel_Closed );
return true;
}
private void Channel_Closed( object sender, EventArgs e )
{
Storage.Deactivate( ( sender as IContextChannel ).SessionId );
}
}
Вспомогательный класс, используемый для отслеживания информации о сеансе :
public class SessionStorage
{
private Dictionary<string, string> Names { get; set; }
public SessionStorage()
{
Names = new Dictionary<string, string>();
}
public void Activate( string sessionId, string name )
{
Names[ name ] = sessionId;
}
public void Deactivate( string sessionId )
{
string name = ( from n in Names where n.Value == sessionId select n.Key ).FirstOrDefault();
if ( name == null )
return;
Names.Remove( name );
}
public bool IsActive( string name )
{
return Names.ContainsKey( name );
}
}
EDIT :
После активации первого сеанса каждый следующий запрос сеанса будет вызывать System.ServiceModel.Security.SecurityAccessDeniedException: доступ запрещен. исключение, которое будет выдано.