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