如何:为服务创建自定义授权管理器

Windows Communication Foundation (WCF) 中的标识模型基础结构支持基于声明的可扩展授权模型。 声明是从令牌中提取的,自定义授权策略将有选择地对其进行处理,然后放入 AuthorizationContext 中。 授权管理器检查 AuthorizationContext 中的声明,从而作出授权决策。

默认情况下,授权决策由 ServiceAuthorizationManager 类作出;但是,可通过创建自定义授权管理器来覆盖这些决策。 若要创建自定义授权管理器,请创建一个从 ServiceAuthorizationManager 派生的类,并实现 CheckAccessCore 方法。 授权决策是在 CheckAccessCore 方法中作出的,如果允许访问,该方法返回 true,如果拒绝访问,则返回 false

如果授权决策取决于消息正文的内容,请使用 CheckAccess 方法。

由于性能问题,如有可能,应重新设计应用程序,使授权决策不需要访问消息正文。

在代码或配置中,可以进行服务的自定义授权管理器注册。

创建自定义授权管理器

  1. ServiceAuthorizationManager 类派生一个类。

    public class MyServiceAuthorizationManager : ServiceAuthorizationManager
    {
    
    
    Public Class MyServiceAuthorizationManager
        Inherits ServiceAuthorizationManager
    
    
  2. 重写 CheckAccessCore(OperationContext) 方法。

    使用传给 OperationContext 方法的 CheckAccessCore(OperationContext) 进行授权决策。

    下面的代码示例使用 FindClaims(String, String) 方法查找自定义声明 http://www.contoso.com/claims/allowedoperation,从而做出授权决策。

    protected override bool CheckAccessCore(OperationContext operationContext)
    {
      // Extract the action URI from the OperationContext. Match this against the claims
      // in the AuthorizationContext.
      string action = operationContext.RequestContext.RequestMessage.Headers.Action;
    
      // Iterate through the various claim sets in the AuthorizationContext.
      foreach(ClaimSet cs in operationContext.ServiceSecurityContext.AuthorizationContext.ClaimSets)
      {
        // Examine only those claim sets issued by System.
        if (cs.Issuer == ClaimSet.System)
        {
          // Iterate through claims of type "http://www.contoso.com/claims/allowedoperation".
            foreach (Claim c in cs.FindClaims("http://www.contoso.com/claims/allowedoperation", Rights.PossessProperty))
          {
            // If the Claim resource matches the action URI then return true to allow access.
            if (action == c.Resource.ToString())
              return true;
          }
        }
      }
    
      // If this point is reached, return false to deny access.
      return false;
    }
    
    Protected Overrides Function CheckAccessCore(ByVal operationContext As OperationContext) As Boolean
        ' Extract the action URI from the OperationContext. Match this against the claims.
        ' in the AuthorizationContext.
        Dim action As String = operationContext.RequestContext.RequestMessage.Headers.Action
    
        ' Iterate through the various claimsets in the AuthorizationContext.
        Dim cs As ClaimSet
        For Each cs In operationContext.ServiceSecurityContext.AuthorizationContext.ClaimSets
            ' Examine only those claim sets issued by System.
            If cs.Issuer Is ClaimSet.System Then
                ' Iterate through claims of type "http://www.contoso.com/claims/allowedoperation".
                Dim c As Claim
                For Each c In cs.FindClaims("http://www.contoso.com/claims/allowedoperation", _
                     Rights.PossessProperty)
                    ' If the Claim resource matches the action URI then return true to allow access.
                    If action = c.Resource.ToString() Then
                        Return True
                    End If
                Next c
            End If
        Next cs
        ' If this point is reached, return false to deny access.
        Return False
    
    End Function
    

使用代码注册自定义授权管理器

  1. 创建自定义授权管理器的一个实例,然后将其分配给 ServiceAuthorizationManager 属性。

    使用 ServiceAuthorizationBehavior 属性可以访问 Authorization

    下面的代码示例注册 MyServiceAuthorizationManager 自定义授权管理器。

    // Add a custom authorization manager to the service authorization behavior.
    serviceHost.Authorization.ServiceAuthorizationManager =
               new MyServiceAuthorizationManager();
    
    ' Add a custom authorization manager to the service authorization behavior.
    serviceHost.Authorization.ServiceAuthorizationManager = _
        New MyServiceAuthorizationManager()
    
    

使用配置注册自定义授权管理器

  1. 打开服务的配置文件。

  2. <serviceAuthorization> 添加到<behaviors>

    <serviceAuthorization> 中,添加一个 serviceAuthorizationManagerType 属性,并将其值设置为表示自定义授权管理器的类型。

  3. 添加一个保护客户端和服务之间的通信的绑定。

    为此通信选择的绑定决定了添加到 AuthorizationContext 的声明,自定义授权管理器使用这些声明来进行授权决策。 有关系统提供的绑定的更多详细信息,请参阅系统提供的绑定

  4. 将行为与服务终结点关联,具体方法是,添加一个 <service> 元素,并将 behaviorConfiguration 属性的值设置为 <behavior> 元素的名称属性的值。

    有关配置服务终结点的详细信息,请参阅如何:在配置中创建服务终结点

    下面的代码示例注册自定义授权管理器 Samples.MyServiceAuthorizationManager

    <configuration>
      <system.serviceModel>
        <services>
          <service
              name="Microsoft.ServiceModel.Samples.CalculatorService"
              behaviorConfiguration="CalculatorServiceBehavior">
            <host>
              <baseAddresses>
                <add baseAddress="http://localhost:8000/ServiceModelSamples/service"/>
              </baseAddresses>
            </host>
            <endpoint address=""
                      binding="wsHttpBinding_Calculator"
                      contract="Microsoft.ServiceModel.Samples.ICalculator" />
          </service>
        </services>
        <bindings>
          <WSHttpBinding>
           <binding name = "wsHttpBinding_Calculator">
             <security mode="Message">
               <message clientCredentialType="Windows"/>
             </security>
            </binding>
          </WSHttpBinding>
        </bindings>
        <behaviors>
          <serviceBehaviors>
            <behavior name="CalculatorServiceBehavior">
              <serviceAuthorization serviceAuthorizationManagerType="Samples.MyServiceAuthorizationManager,MyAssembly" />
             </behavior>
         </serviceBehaviors>
       </behaviors>
      </system.serviceModel>
    </configuration>
    

    警告

    请注意,当您指定了 serviceAuthorizationManagerType 时,字符串必须包含完全限定的类型名称、 一个逗号,以及在其中定义类型的程序集的名称。 如果您忽略了程序集名称,WCF 会尝试从 System.ServiceModel.dll 加载类型。

示例

下面的代码示例演示 ServiceAuthorizationManager 类的一个基本实现,包括重写 CheckAccessCore 方法。 该示例代码检查某个自定义声明的 AuthorizationContext,如果该自定义声明的资源与 true 中的操作值匹配,则返回 OperationContext。 有关 ServiceAuthorizationManager 类的更完整实现,请参阅授权策略

public class MyServiceAuthorizationManager : ServiceAuthorizationManager
{
  protected override bool CheckAccessCore(OperationContext operationContext)
  {
    // Extract the action URI from the OperationContext. Match this against the claims
    // in the AuthorizationContext.
    string action = operationContext.RequestContext.RequestMessage.Headers.Action;
  
    // Iterate through the various claim sets in the AuthorizationContext.
    foreach(ClaimSet cs in operationContext.ServiceSecurityContext.AuthorizationContext.ClaimSets)
    {
      // Examine only those claim sets issued by System.
      if (cs.Issuer == ClaimSet.System)
      {
        // Iterate through claims of type "http://www.contoso.com/claims/allowedoperation".
          foreach (Claim c in cs.FindClaims("http://www.contoso.com/claims/allowedoperation", Rights.PossessProperty))
        {
          // If the Claim resource matches the action URI then return true to allow access.
          if (action == c.Resource.ToString())
            return true;
        }
      }
    }
  
    // If this point is reached, return false to deny access.
    return false;
  }
}

Public Class MyServiceAuthorizationManager
    Inherits ServiceAuthorizationManager

    Protected Overrides Function CheckAccessCore(ByVal operationContext As OperationContext) As Boolean
        ' Extract the action URI from the OperationContext. Match this against the claims.
        ' in the AuthorizationContext.
        Dim action As String = operationContext.RequestContext.RequestMessage.Headers.Action

        ' Iterate through the various claimsets in the AuthorizationContext.
        Dim cs As ClaimSet
        For Each cs In operationContext.ServiceSecurityContext.AuthorizationContext.ClaimSets
            ' Examine only those claim sets issued by System.
            If cs.Issuer Is ClaimSet.System Then
                ' Iterate through claims of type "http://www.contoso.com/claims/allowedoperation".
                Dim c As Claim
                For Each c In cs.FindClaims("http://www.contoso.com/claims/allowedoperation", _
                     Rights.PossessProperty)
                    ' If the Claim resource matches the action URI then return true to allow access.
                    If action = c.Resource.ToString() Then
                        Return True
                    End If
                Next c
            End If
        Next cs
        ' If this point is reached, return false to deny access.
        Return False

    End Function
End Class

另请参阅