实现自定义权限

所有权限对象都必须实现 IPermission 接口。 从 CodeAccessPermission 类继承是创建自定义权限的最简单的方式,因为 CodeAccessPermission 实现了 IPermission 并且提供了权限所需的大多数方法。 另外,必须为所有自定义代码访问权限实现 IUnrestrictedPermission 接口。 强制性和声明式安全支持都需要自定义权限类,所以,即使您计划只使用声明式安全性,也应当创建自定义权限类。

注意注意

自定义权限应定义在不引用它的程序集中。如果自定义权限包含声明式安全的安全特性,则自定义权限和该特性必须定义在不同的程序集中。这是因为,安全特性是在程序集加载时执行的,且在遇到对该特性的引用时,可能还未创建该特性。如果尝试在定义声明式权限的程序集中使用该权限,将导致引发 TypeLoadException

定义权限类

若要从 CodeAccessPermission 类进行派生,必须重写下面的五个关键方法并提供自己的实现:

  • Copy 创建当前权限对象的副本。

  • Intersect 返回当前类与传递的类所允许权限的交集。

  • 如果传递的权限包括当前权限允许的一切操作,则 IsSubsetOf 返回 true。

  • FromXml 对您的自定义权限的 XML 表示形式进行解码。

  • ToXml 对您的自定义权限的 XML 表示形式进行编码。

  • Union 创建一个权限,该权限是当前权限与指定权限的并集。

IUnrestrictedPermission 接口要求您重写并实现一个名为 IsUnrestrictedPermission 的方法。 为了支持 IUnrestrictedPermission 接口,您必须实现某些系统(如表示当前对象中的限制状态的布尔值),以定义权限的当前实例是否为无限制的。

下面的代码段阐释可用来定义自定义权限类的方式。 接受 PermissionState 枚举的构造函数和名为 unrestricted 的布尔值均已创建。 PermissionState 枚举的值可以是 UnrestrictedNone。 如果传递的枚举的值为 Unrestricted,则构造函数将 unrestricted 设置为 true。 否则 unrestricted 将设置为 false。 除特定于您的自定义权限的构造函数外,所有的代码访问权限(从 CodeAccessPermission 继承的所有权限)都必须支持只采用 PermissionState 枚举的构造函数。

除下面的示例中所示的代码外,您还必须实现 IsUnrestricted 方法,并重写 CopyIntersectIsSubsetOfToXMLFromXML 方法。 有关完成这些步骤的信息,请参见示例后面的部分。

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

请注意,该类用 SerializableAttribute 标记。 必须使用 SerializableAttribute 标记您的类,才能支持使用特性的声明式语法。 有关创建使用自定义安全对象的自定义特性的信息,请参见添加声明式安全支持

实现 IsUnrestricted 方法

IUnrestrictedPermission 接口需要 IsUnrestricted 方法,该方法仅返回一个布尔值,该值指示该权限的当前实例对该权限保护的资源是否拥有无限制的访问权限。 若要实现此方法,只要返回 unrestricted 值即可。

下面的代码示例实现 IsUnrestricted 方法。

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

重写 Copy 方法

CodeAccessPermission 类需要 Copy 方法,该方法返回当前权限类的副本。

下面的代码阐释如何重写 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;
} 

重写 Intersect 和 IsSubsetOf 方法

所有权限都必须实现 IntersectIsSubsetOf 方法。 必须按下文所示实现这些操作的行为:

  • 如果权限 Y 包括 X 允许的一切操作,则 X.IsSubsetOf(Y) 为 true

  • X.Intersect(Y) 产生一个权限,该权限允许且只允许 X 和 Y 两个权限同时允许的所有操作。

下面的示例阐释如何重写和实现 Intersect 方法。 该方法接受从 IPermission 派生的一个类,并将此类初始化为 CustomPermisison 对象的新实例。 在这种情况下,如果当前对象和传递的对象的值都是无限制,则这两个对象的交集是具有无限制值的最终对象。 但是,如果这两个对象之一的无限制的值为 false,则最终对象的无限制的值也将为 false。 仅在这两个对象均为无限制时,此代码才会返回一个无限制的对象。

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

在下面的示例中,将重写 IsSubsetOf 方法。 为了让此方法返回 true,当前实例和传递的实例允许的操作集必须完全相同。 在此例中,重写方法将 CustomPermission 对象的新实例初始化为传递的权限对象。 如果 unrestricted 值相同,则该方法返回 true。 如果它们不相同,则该方法返回 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);
   }                
}

重写 ToXml 和 FromXml 方法

权限支持 XML 编码,以便权限对象能够保存为 XML 形式;然后使用该 XML 文件,可以将另一权限对象还原为原始值。 若要支持 XML 编码,您的自定义权限必须实现 ISecurityEncodable 接口,该接口定义一个 ToXml 方法和一个 FromXml 方法。 由于这两个方法都是由 CodeAccessPermission 实现的,因此如果您的自定义权限类派生自 CodeAccessPermission,则应该重写这些方法。

表示对象状态的 XML 元素的内容由对象本身确定。 FromXML 方法可以使用任何 XML 表示形式(只要 ToXML 能够解释它并能还原同一状态)。 但是,包含 Permission 元素必须是标准形式。 例如,CustomPermission 的形式可能类似于:

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

IPermission 元素包含三个特性:

  • class:包含类型名称,将由包含它的程序集的名称来消除该类型名称的歧义。

  • version:指定 XML 编码的版本(不是类的程序集的版本)。

  • Unrestricted:指定权限是否有无限制的权限。

必须在名为 IPermission 的 XML 元素中对所有权限进行编码,以便公共语言运行时安全系统使用这些权限。

权限对象的新版本应当向后兼容,与来自早期版本的、以 XML 形式保持的信息兼容。 版本标记向权限对象提供有关最初对数据进行编码的版本的信息。

SecurityElement 类封装了在创建 XML 编码的权限对象以及与这些对象交互时所需的主要功能。 但是,因为用于 .NET Framework 安全性的 XML 对象模型与其他 XML 对象模型不同,所以不应当使用 SecurityElement 类来生成其他类型的 XML 文件。 有关 SecurityElement 类的成员的完整列表,请参见该类的说明。

下面的代码段创建一个 XML Permission 元素:

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

注意,前面的示例使用了 StringBuilder.Replace 方法。 SecurityElement 类中的特性不能包含双引号,但一些程序集名称信息放在了双引号内。 为处理此情况,使用 Replace 方法将程序集名称中的双引号 (") 转换为单引号 (')。

下面的方法读取由前面的方法创建的 SecurityElement 对象,并将 Unrestricted 属性的当前值设置为所传递对象指定的值。 此方法应确保检索 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);
   }
}

自定义权限示例

下面的代码示例说明整个自定义权限类:

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

请参见

参考

IPermission

CodeAccessPermission

IUnrestrictedPermission

SerializableAttribute

ISecurityEncodable

SecurityElement

概念

创建自己的代码访问权限

代码访问安全性

添加声明式安全支持