Freigeben über


Implementieren einer benutzerdefinierten Berechtigung

Aktualisiert: November 2007

Alle Berechtigungsobjekte müssen die IPermission-Schnittstelle implementieren. Am einfachsten erstellen Sie eine benutzerdefinierte Berechtigung durch Vererbung von der CodeAccessPermission-Klasse, da CodeAccessPermissionIPermission implementiert und den Großteil der für eine Berechtigung erforderlichen Methoden bereitstellt. Darüber hinaus müssen Sie die IUnrestrictedPermission-Schnittstelle für alle benutzerdefinierten Codezugriffsberechtigungen implementieren. Die benutzerdefinierte Berechtigungsklasse wird für die Unterstützung imperativer und deklarativer Sicherheit benötigt. Sie müssen sie darum selbst dann erstellen, wenn Sie lediglich deklarative Sicherheit verwenden möchten.

Hinweis:

Die benutzerdefinierte Berechtigung sollte in einer anderen Assembly definiert werden als der, von der aus auf sie verwiesen wird. Wenn die benutzerdefinierte Berechtigung ein Sicherheitsattribut für deklarative Sicherheit beinhaltet, müssen die benutzerdefinierte Berechtigung und das Attribut in einer separaten Assembly definiert werden. Das liegt daran, dass das Attribut beim Laden der Assembly ausgeführt wird und das Attribut möglicherweise noch nicht erstellt wurde, wenn sein Verweis festgestellt wird. Der Versuch, eine deklarative Berechtigung in der gleichen Assembly zu verwenden, in der sie definiert ist, löst eine TypeLoadException aus.

Definieren der Berechtigungsklasse

Zum Ableiten aus der CodeAccessPermission-Klasse müssen Sie die folgenden fünf Hauptmethoden überschreiben und eine eigene Implementierung angeben:

  • Copy erstellt ein Duplikat des aktuellen Berechtigungsobjekts.

  • Intersect gibt die Schnittmenge der zulässigen Berechtigungen der aktuellen Klasse und einer übergebenen Klasse zurück.

  • IsSubsetOf gibt true zurück, wenn eine übergebene Berechtigung alles enthält, was die aktuelle Berechtigung zulässt.

  • FromXml decodiert eine XML-Darstellung der benutzerdefinierten Berechtigung.

  • ToXml codiert eine XML-Darstellung der benutzerdefinierten Berechtigung.

  • Union erstellt eine Berechtigung, die die Union der aktuellen und der angegebenen Berechtigung ist.

Für die IUnrestrictedPermission-Schnittstelle ist es erforderlich, eine einzige Methode mit der Bezeichnung IsUnrestrictedPermission zu überschreiben und zu implementieren. Für die Unterstützung der IUnrestrictedPermission-Schnittstelle müssen Sie ein System implementieren, z. B. einen booleschen Wert, der den Zustand der Einschränkung im aktuellen Objekt darstellt. Damit definieren Sie, ob die aktuelle Instanz der Berechtigung uneingeschränkt ist.

Das folgende Codefragment veranschaulicht, auf welche Weise eine benutzerdefinierte Berechtigungsklasse definiert werden kann. Es werden sowohl ein Konstruktor, der eine PermissionState-Enumeration annimmt, als auch der boolesche Wert unrestricted erstellt. Die PermissionState-Enumeration weist entweder den Wert Unrestricted oder None auf. Wenn die übergebene Enumeration den Wert Unrestricted hat, legt der Konstruktor unrestricted auf True fest. Andernfalls wird unrestricted auf False festgelegt. Neben den spezifischen Konstruktoren der benutzerdefinierten Berechtigung müssen alle Codezugriffsberechtigungen (alle Berechtigungen, die von CodeAccessPermission erben) einen Konstruktor unterstützen, der lediglich eine PermissionState-Enumeration annimmt.

Zusätzlich zum Code im folgenden Beispiel müssen Sie die IsUnrestricted-Methode implementieren und die Copy-, Intersect-, IsSubsetOf-, ToXML- und FromXML-Methode überschreiben. Informationen über das Ausführen dieser Schritte finden Sie in den Abschnitten im Anschluss an das Beispiel.

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

Beachten Sie, dass die Klasse mit SerializableAttribute markiert wird. Sie müssen die Klasse mit SerializableAttribute kennzeichnen, um die Verwendung eines Attributs durch die deklarative Syntax zu unterstützen. Informationen zum Erstellen eines benutzerdefinierten Attributs, das ein benutzerdefiniertes Sicherheitsobjekt verwendet, finden Sie unter Hinzufügen der Unterstützung der deklarativen Sicherheit.

Implementieren der IsUnrestricted-Methode

Die IsUnrestricted-Methode ist für die IUnrestrictedPermission-Schnittstelle erforderlich. Sie gibt einen booleschen Wert zurück, der angibt, ob die aktuelle Instanz der Berechtigung über uneingeschränkten Zugriff auf die von der Berechtigung geschützte Ressource verfügt. Geben Sie zum Implementieren dieser Methode einfach den Wert unrestricted zurück.

Im folgenden Codebeispiel wird die IsUnrestricted-Methode implementiert.

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

Überschreiben der Copy-Methode

Die Copy-Methode ist für die CodeAccessPermission-Klasse erforderlich. Sie gibt eine Kopie der aktuellen Berechtigungsklasse zurück.

Der folgende Code veranschaulicht das Überschreiben der Copy-Methode.

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

Überschreiben der Intersect-Methode und der IsSubsetOf-Methode

Sämtliche Berechtigungen müssen die Intersect-Methode und die IsSubsetOf-Methode implementieren. Das Verhalten dieser Operationen muss wie folgt implementiert werden:

  • X.IsSubsetOf(Y) ist True, wenn Berechtigung Y sämtliche von X zugelassenen Elemente umfasst.

  • X.Intersect(Y) resultiert in einer Berechtigung, die alle Operationen zulässt, die sowohl von Berechtigung X als auch Berechtigung Y zugelassen werden.

Das folgende Beispiel veranschaulicht das Überschreiben und Implementieren der Intersect-Methode. Die Methode akzeptiert eine von IPermission abgeleitete Klasse und initialisiert diese Klasse mit einer neuen Instanz des CustomPermission-Objekts. In diesem Fall ist die Schnittmenge des aktuellen Objekts und des übergebenen Objekts ein endgültiges Objekt mit dem Wert unrestricted, wenn beide Objekte diesen Wert aufweisen. Wenn jedoch eines der beiden Objekte den Wert False für unrestricted aufweist, hat das endgültige Objekt ebenfalls den Wert False für unrestricted. Dieser Code gibt nur dann ein uneingeschränktes Objekt zurück, wenn beide Objekte uneingeschränkt sind.

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

Im folgenden Beispiel wird die IsSubsetOf-Methode überschrieben. Damit diese Methode True zurückgibt, müssen die aktuelle Instanz und eine übergebene Instanz genau dieselbe Gruppe von Operationen zulassen. In diesem Fall initialisiert die überschriebene Methode eine neue Instanz des CustomPermission-Objekts mit dem übergebenen Berechtigungsobjekt. Wenn die unrestricted-Werte identisch sind, gibt die Methode True zurück. Wenn dies nicht der Fall ist, gibt die Methode False zurück.

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

Überschreiben der ToXml-Methode und der FromXml-Methode

Berechtigungen unterstützen XML-Codierung, sodass ein Berechtigungsobjekt im XML-Format gespeichert werden und anschließend ein anderes Berechtigungsobjekt mithilfe der XML-Datei mit den ursprünglichen Werten wiederhergestellt werden kann. Für die Unterstützung von XML-Codierung muss die benutzerdefinierte Berechtigung die ISecurityEncodable-Schnittstelle implementieren, die eine ToXml-Methode und eine FromXml-Methode definiert. Da beide Methoden von CodeAccessPermission implementiert werden, müssen Sie diese Methoden überschreiben, wenn die benutzerdefinierte Berechtigungsklasse von CodeAccessPermission abgeleitet ist.

Der Inhalt des XML-Elements, das den Objektzustand darstellt, wird durch das Objekt selbst bestimmt. Die FromXML-Methode kann eine beliebige XML-Darstellung verwenden, solange ToXML diese interpretieren und denselben Zustand wiederherstellen kann. Das Permission-Element muss jedoch eine Standardform aufweisen. CustomPermission kann z. B. wie folgt aussehen:

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

Das IPermission-Element enthält drei Attribute:

  • class: Enthält den Typnamen, der durch den Namen der Assembly eindeutig bestimmt wird, in der er enthalten ist.

  • version: Gibt die Version der XML-Codierung an (nicht die Version der Assembly der Klasse).

  • Unrestricted: Gibt an, ob die Berechtigung über unbeschränkte Rechte verfügt.

Alle Berechtigungen müssen in einem XML-Element mit der Bezeichnung IPermission codiert werden, damit sie vom Sicherheitssystem der Common Language Runtime verwendet werden können.

Neue Versionen eines Berechtigungsobjekts müssen abwärtskompatibel mit Daten sein, die mit früheren XML-Versionen erstellt wurden. Das Versionstag stellt für ein Berechtigungsobjekt Informationen über die Version bereit, mit der die Daten ursprünglich codiert wurden.

Die SecurityElement-Klasse kapselt die Hauptfunktionen, die Sie zum Erstellen von und Interagieren mit XML-codierten Berechtigungsobjekten benötigen. Da sich jedoch das XML-Objektmodell für die .NET Framework-Sicherheit von anderen XML-Objektmodellen unterscheidet, dürfen keine anderen XML-Dateitypen mit der SecurityElement-Klasse generiert werden. In der Beschreibung der SecurityElement-Klasse finden Sie eine vollständige Liste der Member dieser Klasse.

Im folgenden Codefragment wird ein XML-codiertes Permission-Element erstellt:

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

Wie Sie sehen, wird im obigen Beispiel die StringBuilder.Replace-Methode verwendet. In der SecurityElement-Klasse dürfen Attribute keine doppelten Anführungszeichen enthalten. Einige Informationen über Assemblynamen sind jedoch in doppelte Anführungszeichen eingeschlossen. Daher wandelt die Replace-Methode doppelte Anführungszeichen (") im Assemblynamen in einfache Anführungszeichen (') um.

Die folgende Methode liest ein von der vorherigen Methode erstelltes SecurityElement-Objekt und legt als aktuellen Wert der Unrestricted-Eigenschaft den durch das übergebene Objekt festgelegten Wert fest. Diese Methode soll sicherstellen, dass sämtliche durch die ToXml-Methode gespeicherten Informationen abgerufen werden.

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

Beispiel einer benutzerdefinierten Berechtigung

Das folgende Codebeispiel zeigt eine vollständig benutzerdefinierte Berechtigungsklasse:

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

Siehe auch

Konzepte

Erstellen von eigenen Codezugriffsberechtigungen

Hinzufügen der Unterstützung der deklarativen Sicherheit

Referenz

IPermission

CodeAccessPermission

IUnrestrictedPermission

SerializableAttribute

ISecurityEncodable

SecurityElement

Weitere Ressourcen

Codezugriffssicherheit