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

时间:2009-08-27 18:43:55

标签: wcf service

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

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

    [OperationContract]
    bool Read();


    [OperationContract]
    bool Write();

所有客户都应该可以访问Read()方法

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

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


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

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

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

但它不起作用。读组用户也可以调用Writer()方法,而Writer组用户也可以调用Write()方法。

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

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

4 个答案:

答案 0 :(得分:4)

我不确定如何将AD凭据集成到正常的.NET安全框架中。但是,它是可能的(我会看到我是否可以找到一些链接),一旦你这样做,你应该能够使用标准的安全属性来检查一个“角色”,它与你的AD组相对应: / p>

[OperationContract]
bool Read();

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

要使用AD组,请配置服务行为:

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

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

答案 1 :(得分:4)

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

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

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

你需要有类似的东西:

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

然后您需要从客户端和服务器端点引用该绑定配置。

WsHttpBinding和NetTcpBinding都默认使用Windows客户端凭据,所以开箱即用,除非您完全关闭安全性,否则您应该在这两个绑定中获得Windows凭据支持。

马克

PS:
正如jrista所展示的那样(我之前回答过almost the same question你做过),你真的只需要将PrincipalPermission属性添加到你想要限制属于某个特定组的用户的方法 - 没有手动搞乱需要AD小组成员资格等。

如果您确实必须获取调用您服务的用户所属的群组,则可以查看WindowsIdentity调用的“.Groups”属性:

WindowsIdentity winCaller = ServiceSecurityContext.Current.WindowsIdentity;
foreach(var group in winCaller.Groups)
{
   Console.WriteLine(group.Value);
}

如果您需要呼叫用户的姓名,请使用winCaller.Name。如果您需要用户呼叫的SID,请使用winCaller.User。它没关系 - 没有混乱,没有复杂的代码 - 只需使用它! : - )

答案 2 :(得分:0)

如果您在IIS中托管服务器设置为允许匿名?

答案 3 :(得分:0)

尝试在服务类中的方法上添加Principalpermission属性,而不是在服务接口中的操作协定上。