Procedura: creare un gestore autorizzazioni personalizzato per un servizio
L'infrastruttura del modello di identità in Windows Communication Foundation (WCF) supporta un modello di autorizzazione estendibile basato su attestazioni. Le attestazioni vengono estratte dai token, elaborate facoltativamente da criteri di autorizzazione personalizzati e quindi inserite in una classe AuthorizationContext. Un gestore autorizzazioni esamina le attestazioni contenute nel contesto AuthorizationContext per prendere decisioni di autorizzazione.
Per impostazione predefinita, le decisioni di autorizzazione sono prese dalla classe ServiceAuthorizationManager. È tuttavia possibile creare un gestore autorizzazioni personalizzato per eseguire l'override di queste decisioni. Per creare un gestore autorizzazioni personalizzato, creare una classe che deriva da ServiceAuthorizationManager e che implementa il metodo CheckAccessCore. Le decisioni di autorizzazione sono prese tramite il metodo CheckAccessCore che restituisce true
quando l'accesso è concesso e false
quando l'accesso è negato.
Se la decisione di autorizzazione dipende dal contenuto del corpo del messaggio, utilizzare il metodo CheckAccess.
A causa di problemi riguardanti le prestazioni, è consigliabile ridisegnare l'applicazione, se possibile, in modo tale che per la decisione di autorizzazione non sia necessario l'accesso al corpo del messaggio.
La registrazione del gestore autorizzazioni personalizzato per un servizio può essere eseguita in codice o in configurazione.
Per creare un gestore autorizzazioni personalizzato
Derivare una classe dalla classe ServiceAuthorizationManager.
public class MyServiceAuthorizationManager : ServiceAuthorizationManager {
Public Class MyServiceAuthorizationManager Inherits ServiceAuthorizationManager
Eseguire l'override del metodo CheckAccessCore(OperationContext).
Utilizzare il contesto OperationContext passato al metodo CheckAccessCore(OperationContext) per prendere decisioni di autorizzazione.
Nell'esempio di codice seguente il metodo FindClaims(String, String) viene utilizzato per individuare l'attestazione personalizzata
http://www.contoso.com/claims/allowedoperation
allo scopo di prendere una decisione di autorizzazione.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
Per registrare un gestore autorizzazioni personalizzato in codice
Creare un'istanza del gestore autorizzazioni personalizzato e assegnarla alla proprietà ServiceAuthorizationManager.
Per accedere al comportamento ServiceAuthorizationBehavior è possibile utilizzare la proprietà Authorization.
Nell'esempio di codice seguente viene illustrato come registrare il gestore autorizzazioni personalizzato
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()
Per registrare un gestore autorizzazioni personalizzato in configurazione
Aprire il file di configurazione del servizio.
Aggiungere un elemento <serviceAuthorization> all'elemento <behaviors>.
Per <serviceAuthorization>, aggiungere un attributo
serviceAuthorizationManagerType
e impostarne il valore sul tipo che rappresenta la gestione autorizzazioni personalizzata.Aggiungere un'associazione in grado di proteggere la comunicazione tra client e servizio.
L'associazione scelta per questa comunicazione determina le attestazioni aggiunte al contesto AuthorizationContext utilizzate dal gestore autorizzazioni personalizzato per prendere le decisioni di autorizzazione. Per altre informazioni sui binding forniti dal sistema, vedere Binding forniti dal sistema.
Associare il comportamento a un endpoint del servizio aggiungendo un elemento <service> e impostando il valore dell'attributo
behaviorConfiguration
sul valore dell'attributo name per l'elemento <behavior>.Per altre informazioni sulla configurazione di un endpoint di servizio, vedere Procedura: Creare un endpoint di servizio in Configuration.
Nell'esempio di codice seguente viene illustrato come registrare il gestore autorizzazioni personalizzato
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>
Avviso
Si noti che quando si specifica l'oggetto serviceAuthorizationManagerType, la stringa deve contenere il nome di tipo completo, una virgola e il nome dell'assembly in cui il tipo è definito. Se si omette il nome dell'assembly, WCF tenterà di caricare il tipo da System.ServiceModel.dll.
Esempio
Nell'esempio di codice seguente viene descritta un'implementazione di base di una classe ServiceAuthorizationManager che prevede l'override del metodo CheckAccessCore. Nell'esempio di codice viene eseguita una ricerca all'interno del contesto AuthorizationContext allo scopo di individuare un'attestazione personalizzata e quindi viene restituito true
quando la risorsa relativa a tale attestazione personalizzata corrisponde al valore di azione indicato nel contesto OperationContext. Per un'implementazione più completa di una classe ServiceAuthorizationManager, vedere Criteri di autorizzazione.
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