Como: criar gerenciador de autorização personalizado para um serviço
A infraestrutura do Modelo de Identidade no Windows Communication Foundation (WCF) dá suporte a um modelo extensível de autorização baseado em declaração. As declarações são extraídas de tokens e, opcionalmente, processadas por políticas de autorização personalizadas e, em seguida, colocadas em um AuthorizationContext. Um gerente de autorização examina as declarações na AuthorizationContext para tomar decisões de autorização.
Por padrão, as decisões de autorização são tomadas pela classe ServiceAuthorizationManager; no entanto, essas decisões podem ser substituídas criando um gerenciador de autorização personalizado. Para criar um gerenciador de autorização personalizado, crie uma classe derivada de ServiceAuthorizationManager e implemente o método CheckAccessCore. As decisões de autorização são tomadas no método CheckAccessCore, que retorna true
quando o acesso é concedido e false
quando o acesso é negado.
Se a decisão de autorização depender do conteúdo do corpo da mensagem, use o método CheckAccess.
Devido a problemas de desempenho, se possível, você deverá reprojetar seu aplicativo para que a decisão de autorização não exija acesso ao corpo da mensagem.
O registro do gerenciador de autorização personalizado para um serviço pode ser feito em código ou na configuração.
Para criar um gerenciador de autorização personalizado
Derivar uma classe da classe ServiceAuthorizationManager.
public class MyServiceAuthorizationManager : ServiceAuthorizationManager {
Public Class MyServiceAuthorizationManager Inherits ServiceAuthorizationManager
Substitua o método CheckAccessCore(OperationContext).
Use o OperationContext que é passado para o método CheckAccessCore(OperationContext) para tomar decisões de autorização.
O exemplo de código a seguir usa o método FindClaims(String, String) para localizar a declaração personalizada
http://www.contoso.com/claims/allowedoperation
para tomar uma decisão de autorização.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
Para registrar um gerenciador de autorização personalizado usando código
Crie uma instância do gerenciador de autorização personalizado e atribua-a à propriedade ServiceAuthorizationManager.
A ServiceAuthorizationBehavior pode ser acessada usando a propriedade Authorization.
O exemplo de código a seguir registra o gerenciador de autorização personalizado
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()
Para registrar um gerenciador de autorização personalizado usando configuração
Abra o arquivo de configuração para o serviço.
Adicione um <serviceAuthorization> aos <comportamentos>.
Para o <serviceAuthorization>, adicione um atributo
serviceAuthorizationManagerType
e defina seu valor como o tipo que representa o gerenciador de autorização personalizado.Adicione uma associação que proteja a comunicação entre o cliente e o serviço.
A associação escolhida para essa comunicação determina as declarações que são adicionadas ao AuthorizationContext, que o gerenciador de autorização personalizado usa para tomar decisões de autorização. Para obter mais detalhes sobre as associações fornecidas pelo sistema, consulte Associações fornecidas pelo sistema.
Associe o comportamento a um ponto de extremidade de serviço adicionando um elemento de <serviço> e defina o valor do atributo
behaviorConfiguration
ao valor do atributo de nome para o elemento de <comportamento>.Para obter mais informações sobre como configurar um ponto de extremidade de serviço, consulte Como criar um ponto de extremidade de serviço na configuração.
O exemplo de código a seguir registra o gerenciador de autorização personalizado
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>
Aviso
Observe que quando você especifica o serviceAuthorizationManagerType, a cadeia de caracteres deve conter o nome de tipo totalmente qualificado. uma vírgula e o nome do assembly no qual o tipo é definido. Se você deixar de fora o nome do assembly, o WCF tentará carregar o tipo de System.ServiceModel.dll.
Exemplo
O exemplo de código a seguir demonstra uma implementação básica de uma classe ServiceAuthorizationManager que inclui substituir o método CheckAccessCore. O código de exemplo examina a AuthorizationContext para uma declaração personalizada e retorna true
quando o recurso dessa declaração personalizada corresponde ao valor da ação do OperationContext. Para obter uma implementação mais completa de uma classe ServiceAuthorizationManager, consulte a Política de Autorização.
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