基于用户组限制WCF Web服务功能

基于用户组限制WCF Web服务功能,wcf,service,Wcf,Service,我有一个由C#客户端应用程序使用的WCF Web服务。我还有4个组存储在Active Directory中。客户端应用程序正在传递用户凭据以连接此web服务 Web服务公开客户端应用程序要访问的多个API或方法,如下所示: [OperationContract] bool Read(); [OperationContract] bool Write(); [PrincipalPermission(SecurityAction.Demand, Role = "

我有一个由C#客户端应用程序使用的WCF Web服务。我还有4个组存储在Active Directory中。客户端应用程序正在传递用户凭据以连接此web服务

Web服务公开客户端应用程序要访问的多个API或方法,如下所示:

    [OperationContract]
    bool Read();


    [OperationContract]
    bool Write();
[PrincipalPermission(SecurityAction.Demand, Role = "Readers")]
[OperationContract]
bool Read();

[PrincipalPermission(SecurityAction.Demand, Role = "Writers")]
[OperationContract]
bool Write();
  <system.serviceModel>
    <bindings>
      <basicHttpBinding>
        <binding name="BasicHttpBind">
          <security mode="TransportCredentialOnly">
            <transport clientCredentialType="Windows" proxyCredentialType="Windows" />
          </security>
        </binding>
      </basicHttpBinding>
    </bindings>
    <services>
      <service name="DXDirectory.DXDirectoryService" behaviorConfiguration="DXDirectory.Service1Behavior">
        <!-- Service Endpoints -->
        <endpoint address="" binding="basicHttpBinding" bindingConfiguration="BasicHttpBind"
                  name="BasicBinding" contract="DXDirectory.IDXDirectoryService">
          <!-- 
              Upon deployment, the following identity element should be removed or replaced to reflect the 
              identity under which the deployed service runs.  If removed, WCF will infer an appropriate identity 
              automatically.
          -->
          <identity>
            <dns value="localhost" />
          </identity>
        </endpoint>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="DXDirectory.Service1Behavior">
          <!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
          <serviceMetadata httpGetEnabled="true" />
          <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->
          <serviceDebug includeExceptionDetailInFaults="false" />
          <serviceAuthorization principalPermissionMode="UseWindowsGroups"/>          
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>
Read()方法应可供所有客户端访问

Write()方法只能由属于Active Directory维护的特定windows用户组的用户访问

问题: 我们如何根据客户机在AD中维护的用户组过滤或限制其公开的接口或方法


jrista, 谢谢你的回复。我尝试了与PrincipalPermission相同的指令,如下所示:

    [OperationContract]
    bool Read();


    [OperationContract]
    bool Write();
[PrincipalPermission(SecurityAction.Demand, Role = "Readers")]
[OperationContract]
bool Read();

[PrincipalPermission(SecurityAction.Demand, Role = "Writers")]
[OperationContract]
bool Write();
  <system.serviceModel>
    <bindings>
      <basicHttpBinding>
        <binding name="BasicHttpBind">
          <security mode="TransportCredentialOnly">
            <transport clientCredentialType="Windows" proxyCredentialType="Windows" />
          </security>
        </binding>
      </basicHttpBinding>
    </bindings>
    <services>
      <service name="DXDirectory.DXDirectoryService" behaviorConfiguration="DXDirectory.Service1Behavior">
        <!-- Service Endpoints -->
        <endpoint address="" binding="basicHttpBinding" bindingConfiguration="BasicHttpBind"
                  name="BasicBinding" contract="DXDirectory.IDXDirectoryService">
          <!-- 
              Upon deployment, the following identity element should be removed or replaced to reflect the 
              identity under which the deployed service runs.  If removed, WCF will infer an appropriate identity 
              automatically.
          -->
          <identity>
            <dns value="localhost" />
          </identity>
        </endpoint>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="DXDirectory.Service1Behavior">
          <!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
          <serviceMetadata httpGetEnabled="true" />
          <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->
          <serviceDebug includeExceptionDetailInFaults="false" />
          <serviceAuthorization principalPermissionMode="UseWindowsGroups"/>          
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>
但它不起作用。读组用户还可以调用Writer()方法,而Writer组用户也可以调用Write()方法

我想告诉您的一件事是,我在web.config文件中使用BasicHttpBind,如下所示:

    [OperationContract]
    bool Read();


    [OperationContract]
    bool Write();
[PrincipalPermission(SecurityAction.Demand, Role = "Readers")]
[OperationContract]
bool Read();

[PrincipalPermission(SecurityAction.Demand, Role = "Writers")]
[OperationContract]
bool Write();
  <system.serviceModel>
    <bindings>
      <basicHttpBinding>
        <binding name="BasicHttpBind">
          <security mode="TransportCredentialOnly">
            <transport clientCredentialType="Windows" proxyCredentialType="Windows" />
          </security>
        </binding>
      </basicHttpBinding>
    </bindings>
    <services>
      <service name="DXDirectory.DXDirectoryService" behaviorConfiguration="DXDirectory.Service1Behavior">
        <!-- Service Endpoints -->
        <endpoint address="" binding="basicHttpBinding" bindingConfiguration="BasicHttpBind"
                  name="BasicBinding" contract="DXDirectory.IDXDirectoryService">
          <!-- 
              Upon deployment, the following identity element should be removed or replaced to reflect the 
              identity under which the deployed service runs.  If removed, WCF will infer an appropriate identity 
              automatically.
          -->
          <identity>
            <dns value="localhost" />
          </identity>
        </endpoint>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="DXDirectory.Service1Behavior">
          <!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
          <serviceMetadata httpGetEnabled="true" />
          <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->
          <serviceDebug includeExceptionDetailInFaults="false" />
          <serviceAuthorization principalPermissionMode="UseWindowsGroups"/>          
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>


是否需要为该功能实现wsHttpBinding?如果是,那么如何在我的Web服务中实现wsHttpBinding?

我不知道如何将AD凭据集成到正常的.NET安全框架中。但是,这是可能的(我会看看是否可以找到一些链接),一旦找到,您应该能够使用标准安全属性来检查“角色”,该角色对应于您的广告组:

[OperationContract]
bool Read();

[PrincipalPermission(SecurityAction.Demand, Role = "Writers")]
[OperationContract]
bool Write();
要利用广告组,请配置服务行为:

<system.serviceModel>
  <behaviors>
    <serviceBehaviors>
      <adServiceBehavior>
        <serviceAuthorization principalPermissionMode="UseWindowsGroups" />
      </adServiceBehavior>
    </serviceBehaviors>
  </behaviors>
</system.serviceModel>


我有另一个想法。有时我们甚至不希望在接口上有Write()方法。使用WCF,您可以在单个服务类上实现多个服务契约接口。理想的解决方案可能是创建两个服务契约接口,一个是Read()和Write(),另一个是just Read()。根据登录到客户端的用户的不同,您可以使用Read()接口来访问那些只具有读取权限的用户,也可以使用Read()/Write()接口来访问这两者。这还允许您向不应具有写访问权限的客户端公开最安全的服务契约,同时在内部利用读/写契约进行管理。您永远不会公开可能被这种方式利用的代码。

jrista是正确的-您可以使用内置的Windows授权服务,包括“PrincipalPermission”属性来限制访问

但是:在授权之前,您需要进行身份验证。首先,在决定是否让他(或她)进来之前,你需要知道谁在敲你服务的门

为了做到这一点,您需要确保在邮件交换上使用Windows凭据,并且客户端和服务器必须位于同一个域中(或者位于具有相互信任关系的域中)。此外,您还需要使用wsHttp或netTcp之类的绑定,默认情况下允许并支持Windows凭据,并且需要确保使用和配置绑定安全配置,将Windows凭据从客户端传输到服务器

您需要具备以下功能:

<system.serviceModel>
  <bindings>
    <netTcpBinding>
      <binding name="Secured">
        <security mode="Transport">
          <transport clientCredentialType="Windows" />
        </security>
      </binding>
    </netTcpBinding>
  </bindings>
</system.serviceModel>

如果需要呼叫用户的名称,请使用
winCaller.name
。如果用户调用需要SID,请使用
winCaller.user
。它在那里很好-没有混乱,没有复杂的代码-就用它吧!:-)

尝试将Principalpermission属性添加到服务类中的方法上,而不是服务接口中的操作合约上。

谢谢Marc,请参阅下面的我的评论。如果您在IIS中托管的服务器是否设置为允许匿名?否,未选中匿名,已选中集成Windows身份验证。未选中基本和摘要身份验证。我发现,由于某些原因,WCF无法识别契约接口上的声明性安全性,它必须在实际实现中。