Implementazione di un'autorizzazione personalizzata

È necessario che tutti gli oggetti autorizzazione implementino l'interfaccia IPermission. Il modo più efficace per creare un'autorizzazione personalizzata consiste nell'ereditare dalla classe CodeAccessPermission. La classe CodeAccessPermission, infatti, implementa l'interfaccia IPermission e fornisce la maggior parte dei metodi richiesti per un'autorizzazione. È inoltre necessario implementare l'interfaccia IUnrestrictedPermission per tutte le autorizzazioni di accesso al codice personalizzate. La classe di autorizzazioni personalizzata è necessaria sia per il supporto della sicurezza imperativa che per quello della sicurezza dichiarativa. Sarà quindi necessario creare tale classe anche quando si è pianificato l'utilizzo della sola sicurezza dichiarativa.

NotaNota

L'autorizzazione personalizzata deve essere definita in un assembly diverso dall'assembly in cui vi si fa riferimento.Se l'autorizzazione personalizzata include un attributo di sicurezza per la sicurezza dichiarativa, l'autorizzazione personalizzata e l'attributo devono essere definiti in un assembly separato.Questa condizione è obbligatoria perché l'attributo, eseguito al caricamento dell'assembly, potrebbe non essere stato creato al momento del rilevamento del riferimento.Il tentativo di utilizzare un'autorizzazione dichiarativa nello stesso assembly nel quale è definita comporta la generazione di un oggetto TypeLoadException.

Definizione della classe di autorizzazioni

Per la derivazione dalla classe CodeAccessPermission, è necessario eseguire l'override dei seguenti cinque metodi chiave e fornire un'implementazione personalizzata:

  • Il metodo Copy crea un duplicato dell'oggetto autorizzazione corrente.

  • Il metodo Intersect restituisce l'intersezione delle autorizzazioni consentite della classe corrente e di una classe passata.

  • Il metodo IsSubsetOf restituisce true se un'autorizzazione passata include tutto quanto è consentito dall'autorizzazione corrente.

  • Il metodo FromXml decodifica una rappresentazione XML dell'autorizzazione personalizzata.

  • Il metodo ToXml codifica una rappresentazione XML dell'autorizzazione personalizzata.

  • Il metodo Union crea un'autorizzazione che è l'unione dell'autorizzazione corrente e dell'autorizzazione specificata.

L'interfaccia IUnrestrictedPermission richiede l'esecuzione dell'override e dell'implementazione di un singolo metodo denominato IsUnrestrictedPermission. Per supportare l'interfaccia IUnrestrictedPermission è necessario implementare un sistema, quale un valore booleano che rappresenta lo stato della restrizione nell'oggetto corrente, per stabilire se l'istanza corrente dell'autorizzazione sia o meno priva di restrizioni.

Nel seguente frammento di codice viene illustrata la modalità di definizione di una classe di autorizzazioni personalizzata. Vengono creati un costruttore che accetta un'enumerazione PermissionState e un valore booleano denominato unrestricted. Il valore dell'enumerazione PermissionState può essere Unrestricted o None. Se il valore dell'enumerazione passata è Unrestricted, il costruttore imposta unrestricted su true. Altrimenti, unrestricted viene impostato su false. Oltre ai costruttori specifici dell'autorizzazione personalizzata, è necessario che tutte le autorizzazioni di accesso al codice, vale a dire ogni autorizzazione che eredita da CodeAccessPermission, supporti un costruttore che accetta solo un'enumerazione PermissionState.

Oltre al codice mostrato nell'esempio seguente, è necessario implementare il metodo IsUnrestricted ed eseguire l'override dei metodi Copy, Intersect, IsSubsetOf, ToXML e FromXML. Per informazioni sul completamento dei vari passaggi, vedere le sezioni che seguono l'esempio.

Option Strict
Option Explicit
Imports System
Imports System.Security
Imports System.Security.Permissions
<SerializableAttribute()> NotInheritable Public Class CustomPermission
   Inherits CodeAccessPermission
   Implements IUnrestrictedPermission
   Private unrestricted As Boolean
   
   
   Public Sub New(state As PermissionState)
      If state = PermissionState.Unrestricted Then
         unrestricted = True
      Else
         unrestricted = False
      End If
   End Sub
   'Define the rest of your custom permission here. You must 
   'implement IsUnrestricted and override the Copy, Intersect, 
   'IsSubsetOf, ToXML, and FromXML methods.
End Class
using System;
using System.Security;
using System.Security.Permissions;

[SerializableAttribute()]
public sealed class CustomPermission: CodeAccessPermission, IUnrestrictedPermission
{  
   private bool unrestricted;

   public CustomPermission(PermissionState state)
   {
      if(state == PermissionState.Unrestricted)
      {
         unrestricted = true;
      }
      else
      {
         unrestricted = false;
      }
   }     

   //Define the rest of your custom permission here. You must 
   //implement IsUnrestricted and override the Copy, Intersect, 
   //IsSubsetOf, ToXML, and FromXML methods.
}

Si noti che la classe è contrassegnata con SerializableAttribute. Tale contrassegno SerializableAttribute è necessario per supportare la sintassi dichiarativa che utilizza un attributo. Per informazioni sulla creazione di un attributo personalizzato che utilizza un oggetto di sicurezza personalizzato, vedere Aggiunta del supporto della sicurezza dichiarativa.

Implementazione del metodo IsUnrestricted

Il metodo IsUnrestricted è richiesto dall'interfaccia IUnrestrictedPermission e restituisce semplicemente un valore booleano che indica se l'istanza corrente dell'autorizzazione dispone di accesso diretto alla risorsa da questa protetta. Per implementare questo metodo è sufficiente che venga restituito il valore unrestricted.

Nell'esempio di codice seguente viene implementato il metodo IsUnrestricted.

Public Function IsUnrestricted() As Boolean Implements IUnrestrictedPermission.IsUnrestricted
   Return unrestricted
End Function
public bool IsUnrestricted()
{
   return unrestricted;
}

Override del metodo Copy

Il metodo Copy è richiesto dalla classe CodeAccessPermission e restituisce una copia della classe di autorizzazioni corrente.

Nell'esempio di codice che segue viene mostrato come eseguire l’override del metodo Copy.

Public Overrides Function Copy() As IPermission
   Dim myCopy As New CustomPermission(PermissionState.None)
   
   If Me.IsUnrestricted() Then
      myCopy.unrestricted = True
   Else
      myCopy.unrestricted = False
   End If
   Return myCopy
End Function
public override IPermission Copy()
{
   CustomPermission copy = new CustomPermission(PermissionState.None);

   if(this.IsUnrestricted())
   {
      copy.unrestricted = true;
   }
   else
   {
      copy.unrestricted = false;
   }
   return copy;
} 

Override dei metodi Intersect e IsSubsetOf

È necessario che tutte le autorizzazioni implementino i metodi Intersect e IsSubsetOf e che il comportamento di tali operazioni sia implementato come segue:

  • X.IsSubsetOf(Y) è true se l'autorizzazione Y include tutto quanto è consentito dall'autorizzazione X.

  • Il risultato di X.Intersect(Y) è un'autorizzazione che consente tutte le operazioni consentite sia dall'autorizzazione X che dall'autorizzazione Y ed esclusivamente quelle.

Nell'esempio che segue viene mostrato come eseguire l’override e l'implementazione del metodo Intersect. Il metodo accetta una classe che deriva da IPermission e la inizializza in una nuova istanza dell'oggetto CustomPermisison. In questo caso, l'intersezione dell'oggetto corrente con l'oggetto passato è un oggetto finale che ha valore unrestricted se entrambi gli oggetti hanno questo valore. Se tuttavia per uno degli oggetti il valore di unrestricted è false, anche l'oggetto finale avrà il valore false. Il codice restituisce un oggetto senza restrizioni se entrambi gli oggetti hanno valore unrestricted.

Public Overrides Function Intersect(target As IPermission) As IPermission
   If Nothing Is target Then
      Return Nothing
   End If
   Try
      Dim PassedPermission As CustomPermission = CType(target, CustomPermission)
      If Not PassedPermission.IsUnrestricted() Then
         Return PassedPermission
      End If
      Return Me.Copy()
   Catch InvalidCastException As Exception
      Throw New ArgumentException("Argument_WrongType", Me.GetType().FullName)
      End Try
End Function
public override IPermission Intersect(IPermission target)
{
   try
   {
      if(null == target)
      {
         return null;
      }
      CustomPermission PassedPermission = (CustomPermission)target;

      if(!PassedPermission.IsUnrestricted())
      {
         return PassedPermission;
      }
      return this.Copy();
   }
   catch (InvalidCastException)
   {
      throw new ArgumentException("Argument_WrongType", this.GetType().FullName);
   }                
}

Nell'esempio seguente viene eseguito l'override del metodo IsSubsetOf. Affinché il metodo restituisca true è necessario che l'istanza corrente e un'istanza passata consentano esattamente lo stesso gruppo di operazioni. In questo caso, il metodo sottoposto a override inizializza una nuova istanza dell'oggetto CustomPermission all'oggetto autorizzazione passato. Se i valori di unrestricted sono uguali, il metodo restituisce true. In caso contrario, il metodo restituisce false.

Public Overrides Function IsSubsetOf(target As IPermission) As Boolean
   If Nothing Is target Then
      Return Not Me.unrestricted
   End If
   Try
      Dim passedpermission As CustomPermission = CType(target, CustomPermission)
      If Me.unrestricted = passedpermission.unrestricted Then
         Return True
      Else
         Return False
      End If
   Catch InvalidCastException As Exception
      Throw New ArgumentException("Argument_WrongType", Me.GetType().FullName)
      End Try
End Function
public override bool IsSubsetOf(IPermission target)
{  
   if(null == target)
   {
      return !this.unrestricted;
   }
   try
   {        
      CustomPermission passedpermission = (CustomPermission)target;
      if(this.unrestricted == passedpermission.unrestricted)
      {
         return true;
      }
      else
      {
         return false;
      }
   }
   catch (InvalidCastException)
   {
      throw new ArgumentException("Argument_WrongType", this.GetType().FullName);
   }                
}

Override dei metodi ToXml e FromXml

Le autorizzazioni supportano la codifica XML in modo che un oggetto autorizzazione possa essere salvato in formato XML e un altro oggetto autorizzazione venga ricondotto al valore dell'originale mediante il file XML. Per supportare la codifica XML, l'autorizzazione personalizzata deve implementare l'interfaccia ISecurityEncodable, che definisce un metodo ToXml e un metodo FromXml. Dal momento che entrambi i metodi vengono implementati da CodeAccessPermission, se la classe di autorizzazioni personalizzata deriva da CodeAccessPermission, sarà necessario eseguire l'override di tali metodi.

Il contenuto dell'elemento XML che rappresenta lo stato dell'oggetto è determinato dall'oggetto stesso. Il metodo FromXML può utilizzare qualsiasi rappresentazione XML purché ToXML possa interpretarlo e ripristinare lo stesso stato. È tuttavia necessario che il formato dell'elemento contenitore Permission sia standard. Il formato di CustomPermission potrebbe, ad esempio, essere analogo al seguente:

<IPermission class="CustomPermissions.CustomPermission, CustomPermissionAssembly " version="1" Unrestricted="True">

L'elemento IPermission contiene tre attributi:

  • class: indica il nome del tipo identificato dal nome dell'assembly che lo contiene.

  • version: specifica la versione della codifica XML, non la versione dell'assembly della classe.

  • Unrestricted: specifica se l'autorizzazione prevede diritti senza restrizioni.

È necessario che tutte le autorizzazioni siano codificate in un elemento XML denominato IPermission, per poter essere utilizzate nell'ambito del sistema di sicurezza di Common Language Runtime.

È necessario che le nuove versioni di un oggetto autorizzazione rimangano compatibili con le informazioni delle versioni precedenti mantenute in XML. Il tag della versione fornisce a un oggetto autorizzazione le informazioni relative alla versione che in origine ha codificato i dati.

La classe SecurityElement incapsula la principale funzionalità necessaria a creare gli oggetti autorizzazioni codificati in XML e interagire con essi. Poiché tuttavia il modello di oggetti XML utilizzato per la sicurezza .NET Framework è differente dagli altri modelli di oggetti XML, è necessario che la classe SecurityElement non venga utilizzata per generare altri tipi di file XML. Per esaminare un elenco completo dei membri della classe SecurityElement, vederne la descrizione nell'argomento omonimo.

Mediante il seguente frammento di codice viene creato un elemento Permission in formato XML:

Public Overrides Function ToXml() As SecurityElement
   Dim element As New SecurityElement("IPermission")
   Dim type As Type = Me.GetType()
   Dim AssemblyName As New StringBuilder(type.Assembly.ToString())
   AssemblyName.Replace(ControlChars.Quote, "'"c)
   element.AddAttribute("class", type.FullName & ", " & AssemblyName.ToString)
   element.AddAttribute("version", "1")
   element.AddAttribute("Unrestricted", unrestricted.ToString())
   Return element
End Function
public override SecurityElement ToXml()
{
   SecurityElement element = new SecurityElement("IPermission");
   Type type = this.GetType();
   StringBuilder AssemblyName = new StringBuilder(type.Assembly.ToString());
   AssemblyName.Replace('\"', '\'');
   element.AddAttribute("class", type.FullName + ", " + AssemblyName);
   element.AddAttribute("version", "1");
   element.AddAttribute("Unrestricted", unrestricted.ToString());
   return element;
}

Notare che nell'esempio precedente viene utilizzato il metodo StringBuilder.Replace. Benché gli attributi della classe SecurityElement non possano contenere virgolette doppie, alcune informazioni relative al nome di assembly sono racchiuse tra virgolette doppie. Per gestire questa situazione, il metodo Replace converte le virgolette doppie (") utilizzate per specificare il nome dell'assembly in virgolette singole (').

Il metodo seguente legge un oggetto SecurityElement creato dal metodo precedente e imposta il valore corrente della proprietà Unrestricted su quello specificato dall'oggetto passato. In questo modo viene garantito il recupero di tutte le informazioni memorizzate nel metodo ToXml.

Public Overrides Sub FromXml(PassedElement As SecurityElement)
   Dim element As String = PassedElement.Attribute("Unrestricted")
   If Not element Is Nothing Then
      Me.unrestricted = Convert.ToBoolean(element)
   End If
End Sub
public override void FromXml(SecurityElement PassedElement)
{
   string element = PassedElement.Attribute("Unrestricted");
   if(null != element)
   {  
      this.unrestricted = Convert.ToBoolean(element);
   }
}

Esempio di autorizzazione personalizzata

Nell'esempio di codice seguente viene mostrata un'intera classe di autorizzazioni personalizzata:

Option Explicit
Option Strict
Imports System
Imports System.Text
Imports System.Security
Imports System.Security.Permissions
Imports Microsoft.VisualBasic

<Serializable()>NotInheritable Public Class CustomPermission
   Inherits CodeAccessPermission
   Implements IUnrestrictedPermission
   Private unrestricted As Boolean
   Public Sub New(state As PermissionState)
      If state = PermissionState.Unrestricted Then
         unrestricted = True
      Else
         unrestricted = False
      End If
   End Sub

   Public Function IsUnrestricted() As Boolean Implements IUnrestrictedPermission.IsUnrestricted
      Return unrestricted
   End Function

   Public Overrides Function Copy() As IPermission
      'Create a new instance of CustomPermission with the current
      'value of unrestricted.
      Dim myCopy As New CustomPermission(PermissionState.None)
      
      If Me.IsUnrestricted() Then
         myCopy.unrestricted = True
      Else
         myCopy.unrestricted = False
      End If
      'Return the copy.
      Return copy
   End Function

   Public Overrides Function Intersect(target As IPermission) As IPermission
      'If nothing was passed, return null.
      If Nothing Is target Then
         Return Nothing
      End If
      Try
         'Create a new instance of CustomPermission from the passed object.
         Dim PassedPermission As CustomPermission = CType(target, CustomPermission)
         'If one class has an unrestricted value of false, then the
         'intersection will have an unrestricted value of false.
         'Return the passed class with the unrestricted value of false.
         If Not PassedPermission.unrestricted Then
            Return target
         End If
         'Return a copy of the current class if the passed one has
         'an unrestricted value of true.
         Return Me.Copy()

      'Catch an InvalidCastException.
      'Throw ArgumentException to notify the user.
      Catch InvalidCastException As Exception
         Throw New ArgumentException("Argument_WrongType", Me.GetType().FullName)
      End Try

   End Function

   Public Overrides Function IsSubsetOf(target As IPermission) As Boolean
      'If nothing was passed and unrestricted is false,
      ' return true. 
 
      If Nothing Is target Then
         Return Not Me.unrestricted
      End If
      Try
         'Create a new instance of CustomPermission from the passed object.
         Dim passedpermission As CustomPermission = CType(target, CustomPermission)
         'If unrestricted has the same value in both objects, then
         'one is the subset of the other.
         If Me.unrestricted = passedpermission.unrestricted Then
            Return True
         Else
            Return False
         End If

      'Catch an InvalidCastException.
      'Throw ArgumentException to notify the user.
      Catch InvalidCastException As Exception
         Throw New ArgumentException("Argument_WrongType", Me.GetType().FullName)
      End Try

   End Function
   
   
   Public Overrides Sub FromXml(PassedElement As SecurityElement)
      'Get the unrestricted value from the XML and initialize 
      'the current instance of unrestricted to that value.
      Dim element As String = PassedElement.Attribute("Unrestricted")
      If Not element Is Nothing Then
         Me.unrestricted = Convert.ToBoolean(element)
   End If
   End Sub
   
   
   Public Overrides Function ToXml() As SecurityElement
      'Encode the current permission to XML using the 
      'SecurityElement class.
      Dim element As New SecurityElement("IPermission")
      Dim type As Type = Me.GetType()
      Dim AssemblyName As New StringBuilder(type.Assembly.ToString())
      AssemblyName.Replace(ControlChars.Quote, "'"c)
      element.AddAttribute("class", type.FullName & ", " & AssemblyName.ToString)
      element.AddAttribute("version", "1")
      element.AddAttribute("Unrestricted", unrestricted.ToString())
      Return element
   End Function
End Class
using System;
using System.Text;
using System.Security;
using System.Security.Permissions;

[Serializable()]
public sealed class CustomPermission: CodeAccessPermission , IUnrestrictedPermission
{
   private bool unrestricted;

   public CustomPermission(PermissionState state)
   {
      if(state == PermissionState.Unrestricted)
      {
         unrestricted = true;
      }
      else
      {
         unrestricted = false;
      }
   }
      
   public bool IsUnrestricted()
   {
      return unrestricted;
   }

   public override IPermission Copy()
   {
      //Create a new instance of CustomPermission with the current
      //value of unrestricted.
      CustomPermission copy = new CustomPermission(PermissionState.None);

      if(this.IsUnrestricted())
      {
         copy.unrestricted = true;
      }
      else
      {
         copy.unrestricted = false;
      }
      //Return the copy.
      return copy;
   }

   public override IPermission Intersect(IPermission target)
   {
      //If nothing was passed, return null.
      if(null == target)
      {
         return null;
      }
      try
      {
         //Create a new instance of CustomPermission from the passed object.
         CustomPermission PassedPermission = (CustomPermission)target;

         //If one class has an unrestricted value of false, then the
         //intersection will have an unrestricted value of false.
         //Return the passed class with the unrestricted value of false.
         if(!PassedPermission.unrestricted)
         {
            return target;
         }
         //Return a copy of the current class if the passed one has
         //an unrestricted value of true.
         return this.Copy();
      }
      //Catch an InvalidCastException.
      //Throw ArgumentException to notify the user.
      catch (InvalidCastException)
      {
         throw new ArgumentException("Argument_WrongType", this.GetType().FullName);
      }                
   }

   public override bool IsSubsetOf(IPermission target)
   {
      //If nothing was passed and unrestricted is false,
      //then return true. 
      if(null == target)
      {
         return !this.unrestricted;
      }
       try
      {        
         //Create a new instance of CustomPermission from the passed object.
         CustomPermission passedpermission = (CustomPermission)target;

         //If unrestricted has the same value in both objects, then
         //one is the subset of the other.
         if(this.unrestricted == passedpermission.unrestricted)
         {
            return true;
         }
         else
         {
            return false;
         } 
      }
      //Catch an InvalidCastException.
      //Throw ArgumentException to notify the user.
      catch (InvalidCastException)
      {
         throw new ArgumentException("Argument_WrongType", this.GetType().FullName);
      }                    
   }

   public override void FromXml(SecurityElement PassedElement)
   {
      //Get the unrestricted value from the XML and initialize 
      //the current instance of unrestricted to that value.
      string element = PassedElement.Attribute("Unrestricted");         
 
      if(null != element)
      {  
         this.unrestricted = Convert.ToBoolean(element);
      }
   }

   public override SecurityElement ToXml()
   {
      //Encode the current permission to XML using the 
      //SecurityElement class.
      SecurityElement element = new SecurityElement("IPermission");
      Type type = this.GetType();
      StringBuilder AssemblyName = new StringBuilder(type.Assembly.ToString());
      AssemblyName.Replace('\"', '\'');
      element.AddAttribute("class", type.FullName + ", " + AssemblyName);
      element.AddAttribute("version", "1");
      element.AddAttribute("Unrestricted", unrestricted.ToString());
      return element;
   }
}

Vedere anche

Riferimenti

IPermission

CodeAccessPermission

IUnrestrictedPermission

SerializableAttribute

ISecurityEncodable

SecurityElement

Concetti

Creazione di autorizzazioni personalizzate di accesso al codice

Sicurezza dall'accesso di codice

Aggiunta del supporto della sicurezza dichiarativa