Partager via


Implémentation d'une autorisation personnalisée

Mise à jour : novembre 2007

Tous les objets d'autorisation doivent implémenter l'interface IPermission. Hériter de la classe CodeAccessPermission est le moyen le plus simple de créer une autorisation personnalisée puisque CodeAccessPermission implémente IPermission et fournit la plupart des méthodes requises pour une autorisation. De plus, vous devez implémenter l'interface IUnrestrictedPermission pour toutes les autorisations d'accès du code personnalisées. La classe d'autorisations personnalisée est requise pour la prise en charge de la sécurité impérative et déclarative ; vous devriez donc la créer même si vous prévoyez de n'utiliser que la sécurité déclarative.

Remarque :

L'autorisation personnalisée doit être définie dans un assembly différent de celui dans lequel elle est référencée. Si l'autorisation personnalisée inclut un attribut de sécurité pour la sécurité déclarative, l'autorisation personnalisée et l'attribut doivent être définis dans un assembly distinct. En effet, l'attribut de sécurité est exécuté lorsque l'assembly est chargé et l'attribut n'a peut-être pas été créé au moment la référence à cet attribut est rencontrée. Toute tentative d'utiliser une autorisation déclarative dans le même assembly que celui dans lequel elle est définie entraîne la levée d'une TypeLoadException.

Définition de la classe d'autorisations

Pour dériver de la classe CodeAccessPermission, vous devez substituer les cinq méthodes clés suivantes et fournir votre propre implémentation :

  • Copy crée un double de l'objet d'autorisation actuel.

  • Intersect retourne l'intersection des autorisations permises de la classe actuelle et d'une classe passée.

  • IsSubsetOf retourne true si une autorisation passée comprend tout ce qui est permis par l'autorisation actuelle.

  • FromXml décode une représentation XML de votre autorisation personnalisée.

  • ToXml code une représentation XML de votre autorisation personnalisée.

  • Union crée une autorisation correspondant à l'union de l'autorisation actuelle et de l'autorisation spécifiée.

L'interface IUnrestrictedPermission exige que vous substituiez et implémentiez une méthode unique appelée IsUnrestrictedPermission. Afin de prendre en charge l'interface IUnrestrictedPermission, vous devez implémenter un certain système, tel une valeur booléenne qui représente l'état de restriction de l'objet en cours, afin de définir si l'instance actuelle de l'autorisation est illimitée.

Le fragment de code suivant illustre la façon dont une classe d'autorisations personnalisée peut être définie. Un constructeur qui accepte une énumération PermissionState et une valeur booléenne appelée unrestricted sont créés. L'énumération PermissionState a la valeur Unrestricted ou None. Si l'énumération passée a une valeur Unrestricted, le constructeur affecte la valeur true à unrestricted. Sinon, false est affecté à unrestricted. En plus des constructeurs spécifiques à votre autorisation personnalisée, toutes les autorisations d'accès du code (toute autorisation qui hérite de CodeAccessPermission) doivent prendre en charge un constructeur qui ne prend qu'une énumération PermissionState.

En plus du code illustré dans l'exemple suivant, vous devez implémenter la méthode IsUnrestricted et substituer les méthodes Copy, Intersect, IsSubsetOf, ToXML et FromXML. Pour plus d'informations sur l'exécution de ces étapes, consultez les sections ci-après.

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.
}

Notez que la classe est marquée avec la SerializableAttribute. Vous devez marquer votre classe avec SerializableAttribute afin de prendre en charge la syntaxe déclarative à l'aide d'un attribut. Pour plus d'informations sur la création d'un attribut personnalisé qui utilise un objet de sécurité personnalisé, consultez Ajout de la prise en charge de la sécurité déclarative.

Implémentation de la méthode IsUnrestricted

La méthode IsUnrestricted est requise par l'interface IUnrestrictedPermission et retourne simplement une valeur booléenne qui indique si l'instance actuelle de l'autorisation a un accès illimité à la ressource protégée par l'autorisation. Pour implémenter cette méthode, retournez simplement la valeur de unrestricted.

L'exemple de code suivant implémente la méthode IsUnrestricted.

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

Substitution de la méthode Copy

La méthode Copy est requise par la classe CodeAccessPermission et retourne une copie de la classe d'autorisations en cours.

Le code suivant illustre comment substituer la méthode 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;
} 

Substitution des méthodes Intersect et IsSubsetOf

Toutes les autorisations doivent implémenter les méthodes Intersect et IsSubsetOf. Le comportement de ces opérations doit être implémenté comme suit :

  • X.IsSubsetOf(Y) est true si l'autorisation Y inclut tout ce qui est permis par X.

  • X.Intersect(Y) entraîne une autorisation qui permet toutes les opérations et uniquement celles permises par les autorisations X et Y.

L'exemple suivant illustre comment substituer et implémenter la méthode Intersect. La méthode accepte une classe qui dérive de IPermission et initialise cette classe à une nouvelle instance de l'objet CustomPermisison. Dans ce cas, l'intersection de l'objet en cours et de l'objet passé est un objet final ayant la valeur Unrestricted si les deux objets ont cette valeur. Cependant, si l'un des deux objets a une valeur false pour Unrestricted, l'objet final aura alors aussi une valeur false pour Unrestricted. Ce code retourne un objet illimité uniquement si les deux objets sont illimités.

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);
   }                
}

Dans l'exemple suivant, la méthode IsSubsetOf est substituée. Pour que cette méthode retourne true, l'instance actuelle et une instance passée doivent autoriser exactement le même jeu d'opérations. Dans ce cas, la méthode substituée initialise une nouvelle instance de l'objet CustomPermission à l'objet d'autorisation passé. Si les valeurs unrestricted sont les mêmes, la méthode retourne alors true. Si ce n'est pas le cas, la méthode retourne 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);
   }                
}

Substitution des méthodes ToXml et FromXml

Les autorisations prennent en charge le codage XML de manière à ce qu'un objet d'autorisation puisse être enregistré en XML et que la valeur d'origine d'un autre objet d'autorisation puisse ensuite être restaurée à l'aide du fichier XML. Pour prendre en charge le codage XML, votre autorisation personnalisée doit implémenter l'interface ISecurityEncodable qui définit une méthode ToXml et une méthode FromXml. Comme ces deux méthodes sont implémentées par CodeAccessPermission, si votre classe d'autorisations personnalisée dérive de CodeAccessPermission, vous devez substituer ces méthodes.

Le contenu de l'élément XML qui représente l'état de l'objet est déterminé par l'objet lui-même. La méthode FromXML peut utiliser une représentation XML aussi longtemps que ToXML peut l'interpréter et restaurer le même état. Cependant, l'élément Permission contenant doit être un formulaire standard. Par exemple, le formulaire de CustomPermission peut avoir l'apparence suivante :

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

L'élément IPermission contient trois attributs :

  • **class **: contient le nom de type désambiguïsé par le nom de l'assembly qui le contient.

  • **version **: spécifie la version du codage XML (et non la version de l'assembly de la classe).

  • **Unrestricted **: spécifie si l'autorisation a des droits illimités.

Toutes les autorisations doivent être codées en un élément XML appelé IPermission, pour pouvoir être utilisées par le système de sécurité du Common Language Runtime.

Les nouvelles versions d'un objet d'autorisation doivent rester compatibles en amont avec les informations qui persistent dans le code XML des versions précédentes. La balise de version fournit à un objet d'autorisation les informations concernant la version qui a initialement codé les données.

La classe SecurityElement encapsule la fonctionnalité principale dont vous avez besoin afin de créer et d'interagir avec les objets d'autorisation codés en XML . Cependant, étant donné que le modèle d'objet XML utilisé pour la sécurité .NET Framework est différent des autres modèles objet XML, la classe SecurityElement ne doit pas être utilisée pour générer d'autres types de fichiers XML. Consultez la description de la classe SecurityElement pour obtenir une liste complète de ses membres.

Le fragment de code suivant crée un élément Permission 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;
}

Notez que l'exemple précédent utilise la méthode StringBuilder.Replace. Les attributs de la classe SecurityElement ne peuvent pas contenir de guillemets doubles mais certaines informations de nom d'assembly sont entre guillemets doubles. Pour gérer cette situation, la méthode Replace convertit les guillemets doubles (") du nom de l'assembly en guillemets simples (').

La méthode suivante lit un objet SecurityElement créé par la méthode précédente et affecte à la valeur actuelle de la propriété Unrestricted celle qui est spécifiée par l'objet passé. Cette méthode devrait garantir que les informations stockées par la méthode ToXml sont extraites.

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);
   }
}

Exemple d'autorisation personnalisée

L'exemple de code suivant illustre une classe d'autorisations personnalisée complète :

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;
   }
}

Voir aussi

Concepts

Création de vos propres autorisations d'accès du code

Ajout de la prise en charge de la sécurité déclarative

Référence

IPermission

CodeAccessPermission

IUnrestrictedPermission

SerializableAttribute

ISecurityEncodable

SecurityElement

Autres ressources

Sécurité d'accès du code