简体   繁体   English

限制每个用户的并发wcf会话数

[英]Restrict number of concurrent wcf sessions per user

I have a WCF service that is session-based and secure (probably will use federated security). 我有一个基于会话和安全的WCF服务(可能会使用联合安全性)。

I would like to allow only 1 concurrent session per user. 我想每个用户只允许1个并发会话。 For instance bob can open a session and communicated with the server, but if he tries to open another session without closing the first one, he will not succeed. 例如,bob可以打开会话并与服务器通信,但如果他试图打开另一个会话而不关闭第一个会话,他将无法成功。

Does WCF support this out of the box? WCF是否支持开箱即用? Thanks! 谢谢!

I can't think of any way to do it automatically. 我想不出有任何办法自动完成。 But you could do ti manually by keeping a list of sessions ( OperationContext.Current.Channel.SessionId ) and their associated users in memory in your service, perhaps like this: 但是您可以通过在服务的内存中保留会话列表( OperationContext.Current.Channel.SessionId )及其关联用户来手动执行OperationContext.Current.Channel.SessionId ,可能是这样的:

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

Before you process any request, check to see if that user has an entry with a different Guid. 在处理任何请求之前,请检查该用户是否具有包含其他Guid的条目。 If the user does, throw a fault. 如果用户这样做,则抛出一个错误。 If the user doesn't, add the User/Session to your dictionary. 如果用户没有,请将用户/会话添加到您的词典中。 Then add a handler to the OperationContext.Current.Channel.OnClosed event that removes the entry when the user departs. 然后向OperationContext.Current.Channel.OnClosed事件添加一个处理程序,该事件在用户离开时删除该条目。 Perhaps like so: 也许是这样的:

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

Basically, you need to do following: 基本上,您需要执行以下操作:

  1. Configure security on client and service binding so identity is transferred to service. 配置客户端和服务绑定的安全性 ,以便将身份传输到服务。
  2. Implement custom authorization manager that will track sessions and allow/forbid user to use the service. 实现自定义授权管理器,该管理器将跟踪会话并允许/禁止用户使用该服务。
  3. Configure serviceAuthorization behavior to use implemented authorization manager. 配置serviceAuthorization行为以使用实现的授权管理器。

See following configuration and code samples. 请参阅以下配置和代码示例。

Client configuration : 客户端配置

<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>

Service configuration : 服务配置

<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>

Custom authorization manager : 自订授权经理

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 );
    }
}

The helper class used to track session information : 用于跟踪会话信息的帮助程序类

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 : After first session is activated, each following request for a session will cause a System.ServiceModel.Security.SecurityAccessDeniedException: Access is denied. 编辑 :激活第一个会话后,每个后续的会话请求都将导致System.ServiceModel.Security.SecurityAccessDeniedException:拒绝访问。 exception to be thrown. 被抛出的异常。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM