Share via


Implementar un permiso personalizado

Todos los objetos de permiso deben implementar la interfaz IPermission. La manera más fácil de crear un permiso personalizado es heredar de la clase CodeAccessPermission, porque CodeAccessPermission implementa IPermission y proporciona la mayoría de los métodos necesarios para un permiso. Además, se debe implementar la interfaz IUnrestrictedPermission para todos los permisos de acceso a código personalizados. La clase de permiso personalizada es necesaria para la compatibilidad con la seguridad imperativa y declarativa, por lo que debe crearla aunque tenga previsto utilizar sólo la seguridad declarativa.

Definir la clase de permiso

Para derivar de la clase CodeAccessPermission, es preciso reemplazar los cinco métodos principales siguientes y proporcionar una implementación propia:

  • Copy crea un duplicado del objeto de permiso actual.

  • Intersect devuelve la intersección de permisos permitidos de la clase actual y una clase que se ha pasado.

  • IsSubsetOf devuelve true si un permiso que se ha pasado incluye todo lo que permite el permiso actual.

  • FromXml descodifica una representación XML del permiso personalizado.

  • ToXml codifica una representación XML del permiso personalizado.

  • Union crea un permiso que es la unión del permiso actual y el permiso especificado.

La interfaz IUnrestrictedPermission requiere que se reemplace y se implemente un único método denominado IsUnrestrictedPermission. Para admitir la interfaz IUnrestrictedPermission, debe implementar algún sistema, como un valor booleano que represente el estado de restricción del objeto actual, para definir si la instancia actual del permiso no tiene restricciones.

En el siguiente fragmento de código se muestra la forma en que se puede definir una clase de permiso personalizada. Se crean un constructor que acepte una enumeración PermissionState y un valor booleano denominado unrestricted. La enumeración PermissionState tiene el valor Unrestricted o None. Si la enumeración que se ha pasado tiene el valor Unrestricted, el constructor establece unrestricted en true. En caso contrario, unrestricted se establece en false. Además de los constructores específicos del permiso personalizado, todos los permisos de acceso a código (cualquier permiso que se herede de CodeAccessPermission) deben admitir un constructor que utilice sólo una enumeración PermissionState.

Además del código que se muestra en el ejemplo siguiente, debe implementar el método IsUnrestricted y reemplazar los métodos Copy, Intersect, IsSubsetOf, ToXML y FromXML. Para obtener información sobre cómo realizar estos pasos, vea las secciones posteriores al ejemplo.

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

Observe que la clase está marcada con SerializableAttribute. Debe marcar la clase con SerializableAttribute para admitir la sintaxis declarativa mediante un atributo. Para obtener información sobre cómo crear un atributo personalizado que utilice un objeto de seguridad personalizado, vea Agregar compatibilidad con la seguridad declarativa.

Implementar el método IsUnrestricted

La interfaz IUnrestrictedPermission requiere el método IsUnrestricted, que simplemente devuelve un valor booleano que indica si la instancia actual del permiso tiene acceso ilimitado al recurso protegido por el permiso. Para implementar este método, devuelva el valor de unrestricted.

En el siguiente código de ejemplo se implementa el método IsUnrestricted.

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

Reemplazar el método Copy

La clase CodeAccessPermission requiere el método Copy, que devuelve una copia de la actual clase de permiso.

En el código siguiente, se muestra cómo reemplazar el método 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;
} 

Reemplazar los métodos Intersect e IsSubsetOf

Todos los permisos deben implementar los métodos Intersect e IsSubsetOf. El comportamiento de estas operaciones debe implementarse de la manera siguiente:

  • X.IsSubsetOf(Y) es true si el permiso Y incluye todo lo permitido por X.

  • X.Intersect(Y) genera un permiso que permite todas las operaciones y sólo aquellas operaciones permitidas por los permisos X e Y.

En el ejemplo siguiente se muestra cómo reemplazar e implementar el método Intersect. El método acepta una clase que se deriva de IPermission e inicializa esta clase en una nueva instancia del objeto CustomPermisison. En este caso, la intersección del objeto actual y del objeto que se ha pasado es un objeto final con el valor de unrestricted si ambos objetos tienen ese valor. No obstante, si uno de los dos objetos tiene un valor false para unrestricted, el objeto final también tendrá un valor false para unrestricted. Este código devuelve un objeto ilimitado sólo si ambos objetos también lo son.

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

En el ejemplo siguiente, se reemplaza el método IsSubsetOf. Para que este método devuelva true, la instancia actual y la instancia que se pase deben permitir exactamente el mismo conjunto de operaciones. En este caso, el método reemplazado inicializa una nueva instancia del objeto CustomPermission para el objeto de permiso que se ha pasado. Si los valores de unrestricted son iguales, el método devuelve true. En caso contrario, el método devuelve 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);
   }                
}

Reemplazar los métodos ToXml y FromXml

Los permisos admiten la codificación XML con el fin de que un objeto de permiso se pueda guardar como XML y, después, se pueda restaurar otro objeto de permiso con el valor del original, utilizando el archivo XML. Para admitir la codificación XML, el permiso personalizado debe implementar la interfaz ISecurityEncodable, que define un método ToXml y un método FromXml. Dado que CodeAccessPermission implementa ambos métodos, si la clase de permiso personalizada se deriva de CodeAccessPermission, se deberá reemplazar estos métodos.

El contenido del elemento XML que representa el estado del objeto lo determina el propio objeto. El método FromXML puede utilizar cualquier representación XML siempre y cuando ToXML pueda interpretarla y restaurar el mismo estado. Sin embargo, el elemento Permission contenedor debe tener un formato estándar. Por ejemplo, el formato de CustomPermissionpodría ser similar al siguiente:

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

El elemento IPermission contiene tres atributos:

  • class: contiene el nombre de tipo cuya ambigüedad ha sido eliminada por el nombre del ensamblado que lo contiene.

  • version: especifica la versión de la codificación XML (no la versión del ensamblado de la clase).

  • Unrestricted: especifica si el permiso tiene derechos ilimitados.

Todos los permisos deben codificarse en un elemento XML denominado IPermission para que pueda utilizarlos el sistema de seguridad de Common Language Runtime.

Las nuevas versiones de un objeto de permiso deben ser compatibles con la información que se conserva en XML de versiones anteriores. La etiqueta de versión proporciona información a un objeto de permiso sobre qué versión codificó los datos originalmente.

La clase SecurityElement encapsula la funcionalidad principal que se necesita para crear e interactuar con objetos de permiso codificados en XML. Sin embargo, dado que el modelo de objeto XML utilizado para la seguridad de .NET Framework es distinto de otros modelos de objeto XML, no se debe utilizar la clase SecurityElement para generar otros tipos de archivo XML. Para obtener una lista completa de los miembros de la clase SecurityElement, vea su descripción.

En el siguiente fragmento de código se crea un elemento 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;
}

Observe que en el ejemplo anterior se utiliza el método StringBuilder.Replace. Los atributos en la clase SecurityElement no pueden incluir comillas dobles, si bien una parte de la información del nombre del ensamblado las incluye. Para controlar esta situación, el método Replace convierte las comillas dobles (") en el nombre del ensamblado a comillas simples (').

El método siguiente lee un objeto SecurityElement creado por el método anterior y establece el valor actual de la propiedad Unrestricted en el especificado por el objeto que se ha pasado. Este método debe garantizar que se recupera toda la información almacenada por el método 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);
   }
}

Ejemplo de permiso personalizado

En el siguiente código de ejemplo se muestra una clase de permiso personalizada completa:

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

Vea también

Referencia

IPermission Interface
CodeAccessPermission Class
IUnrestrictedPermission Interface
SerializableAttribute Class
ISecurityEncodable Interface
SecurityElement Class

Conceptos

Crear permisos de acceso a código propios
Agregar compatibilidad con la seguridad declarativa

Otros recursos

Seguridad de acceso a código