基本上,您需要执行以下操作:
- 在客户端和服务绑定上配置安全性,以便将身份传输到服务。
- 实施自定义授权管理器,该管理器将跟踪会话并允许/禁止用户使用该服务。
- 配置 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 );
}
}
编辑:
激活第一个会话后,每个后续的会话请求都会导致 System.ServiceModel.Security.SecurityAccessDeniedException: Access is denied. 抛出异常。