如何:为服务创建自定义授权管理器
Windows Communication Foundation (WCF) 中的标识模型基础结构支持基于声明的可扩展授权模型。 声明是从令牌中提取的,自定义授权策略将有选择地对其进行处理,然后放入 AuthorizationContext 中。 授权管理器检查 AuthorizationContext 中的声明,从而作出授权决策。
默认情况下,授权决策由 ServiceAuthorizationManager 类作出;但是,可通过创建自定义授权管理器来覆盖这些决策。 若要创建自定义授权管理器,请创建一个从 ServiceAuthorizationManager 派生的类,并实现 CheckAccessCore 方法。 授权决策是在 CheckAccessCore 方法中作出的,如果允许访问,该方法返回 true
,如果拒绝访问,则返回 false
。
如果授权决策取决于消息正文的内容,请使用 CheckAccess 方法。
由于性能问题,如有可能,应重新设计应用程序,使授权决策不需要访问消息正文。
在代码或配置中,可以进行服务的自定义授权管理器注册。
创建自定义授权管理器
从 ServiceAuthorizationManager 类派生一个类。
public class MyServiceAuthorizationManager : ServiceAuthorizationManager {
Public Class MyServiceAuthorizationManager Inherits ServiceAuthorizationManager
重写 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
使用代码注册自定义授权管理器
创建自定义授权管理器的一个实例,然后将其分配给 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()
使用配置注册自定义授权管理器
打开服务的配置文件。
将 <serviceAuthorization> 添加到<behaviors>。
在 <serviceAuthorization> 中,添加一个
serviceAuthorizationManagerType
属性,并将其值设置为表示自定义授权管理器的类型。添加一个保护客户端和服务之间的通信的绑定。
为此通信选择的绑定决定了添加到 AuthorizationContext 的声明,自定义授权管理器使用这些声明来进行授权决策。 有关系统提供的绑定的更多详细信息,请参阅系统提供的绑定。
将行为与服务终结点关联,具体方法是,添加一个 <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