2011-02-10 2 views
3

세션 기반 보안 WCF 서비스가 있습니다. (아마도 연합 보안을 사용합니다).사용자 당 동시 wcf 세션 수를 제한하십시오.

사용자 당 동시 세션을 1 개 허용하고 싶습니다. 예를 들어 bob은 세션을 열고 서버와 통신 할 수 있지만 첫 번째 세션을 닫지 않고 다른 세션을 열려고하면 성공하지 못합니다.

WCF가이 제품을 즉시 지원합니까? 감사합니다.

+0

왜이 작업을 수행 하시겠습니까? 세션이 너무 비싸습니까? –

+0

예를 들어, 경합이있을 수 있기 때문에 사용자가 2 대의 다른 컴퓨터에서 서비스에 로그인 할 수 없도록하려는 경우 (예 : 다른 컴퓨터에서 Gmail에 로그인하는 경우와 같은 방법으로 원래 컴퓨터에서 시작). –

+0

사실, 원하는만큼의 컴퓨터에서 gmail에 로그인 할 수 있습니다. 하지만 그것은 측면 문제입니다 :-). –

답변

3

나는 자동으로 그렇게 할 생각이 없다. 하지만 당신은 아마도이 같은 서비스에 메모리에 세션 (OperationContext.Current.Channel.SessionId) 및 관련 사용자의 목록을 유지하여 수동으로 TI을 할 수있는 : 당신이 어떤 요청을 처리하기 전에

private static Dictionary<string, Guid> activeSessions = new Dictionary<string, Guid>(); 

, 즉 사용자가이 있는지 확인 다른 Guid를 가진 항목. 사용자가 잘못하면 오류가 발생합니다. 사용자가하지 않으면 사용자/세션을 사전에 추가하십시오. 그런 다음 사용자가 출발 할 때 항목을 제거하는 OperationContext.Current.Channel.OnClosed 이벤트에 처리기를 추가합니다. 아마도과 같이 :

OperationContext.Current.Channel.OnClosed += (s, e) => 
    { 
     Guid sessionId = ((IContextChannel)sender).SessionId; 
     var entry = activeSessions.FirstOrDefault(kvp => kvp.Value == sessionId); 
     activeSessions.Remove(entry.Key); 
    }; 
+0

이 접근 방식에는 큰 문제가 있습니다. 채널을 제대로 닫지 않고 클라이언트가 충돌하면 서비스를 다시 시작할 때까지 다시 연결할 수 없습니다. 그 문제에 대한 해결책이 있습니까? – chris

+0

@Chris - 채널을 닫지 않고 클라이언트가 충돌하면 채널이 계속 닫힙니다. Net.TCP와 같은 연결 지향 바인딩을 사용하고 있다면 즉시 닫힙니다. 긴 폴링 바인딩 중 하나를 사용하는 경우 시간이 초과 될 때까지 시간이 걸릴 수 있습니다. 그러나 "Channel.OnClosed"이벤트는 결국 어느 경우에도 실행됩니다. –

3

는 기본적으로, 당신은 다음을 수행해야합니다 클라이언트와 서비스에

  1. 구성 보안을 그래서 정체성이 서비스로 전송 바인딩.
  2. 세션을 추적하고 사용자가 서비스를 사용하도록 허용/금지하는 사용자 정의 권한 부여 관리자를 구현하십시오.
  3. 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); 
    } 
} 

편집 : 14,도우미 클래스는 세션 정보 추적하는 데 사용 첫 번째 세션이 활성화 된 후를, 세션에 대한 각각 다음과 같은 요청은 System.ServiceModel.Security.SecurityAccessDeniedException가 발생합니다 : 액세스가 거절 당했다. 예외가 발생합니다.

관련 문제