共用方式為


實作自訂使用權限

更新:2007 年 11 月

所有的使用權限物件都必須實作 IPermission 介面。從 CodeAccessPermission 類別繼承是建立自訂使用權限的最簡單方法,因為 CodeAccessPermission 會實作 IPermission,並提供使用權限所需要的大部分方法。此外,您也必須為所有自訂程式碼存取使用權限實作 IUnrestrictedPermission 介面。命令式和宣告式安全性支援同時都需要自訂使用權限類別,因此即使您只想使用宣告式安全性,您也應該建立它。

注意事項:

自訂權限應在其中未參考該權限的組件中定義。如果自訂權限包含宣告式安全性的安全性屬性,則自訂權限和屬性必須在不同的組件中定義。這是因為安全性屬性會在組件載入時執行,而該屬性的參考發生時,屬性可能尚未建立。嘗試在定義宣告式權限的同一個組件中使用該權限,會導致擲回 TypeLoadException

定義使用權限類別

若要衍生自 CodeAccessPermission 類別,您必須覆寫下列五個重要的方法,並提供您自己的實作 (Implementation):

  • Copy 會建立目前使用權限物件的複本。

  • Intersect 會傳回目前類別和所傳遞類別的允許使用權限交集

  • 當所傳遞的使用權限包含任一由目前使用權限允許的項目時,IsSubsetOf 就會傳回 true。

  • FromXml 會解碼自訂使用權限的 XML 表示。

  • ToXml 會編碼自訂使用權限的 XML 表示。

  • Union 會建立做為目前使用權限和所指定使用權限之聯集的使用權限。

IUnrestrictedPermission 介面會要求您覆寫並實作一個名為 IsUnrestrictedPermission 的單一方法。為支援 IUnrestrictedPermission 介面,您必須實作某些系統 (如設定一個表示目前物件其條件限制狀態的布林值),以定義使用權限的目前執行個體是否未受限制。

以下的程式碼片段將說明如何定義自訂使用權限類別。會同時建立接受 PermissionState 列舉型別的建構函式 (Constructor),以及名為 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 方法

IsUnrestricted 方法是 IUnrestrictedPermission 介面需要使用的方法,且只傳回一個布林值,表示使用權限的目前執行個體對由該使用權限保護的資源存取是否未受限制。若要實作這個方法,只需傳回 unrestricted 的值即可。

以下的程式碼範例將實作 IsUnrestricted 方法。

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

覆寫 Copy 方法

Copy 方法是 CodeAccessPermission 類別需要使用的方法,且傳回一份目前使用權限類別的複本。

以下的程式碼將說明如何覆寫 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 方法。實作這些作業的行為必須如下所示:

  • X.IsSubsetOf(Y) 為 True,如使用權限 Y 包含由 X 允許的任何項目。

  • 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 介面,以定義 ToXmlFromXml 方法。因為這兩個方法都是由 CodeAccessPermission 實作,所以當自訂使用權限類別是衍生自 CodeAccessPermission,您應該覆寫這些方法。

表示物件狀態的 XML 項目內容是由物件本身決定。FromXML 方法可以使用任何 XML 表示,而 ToXML 可以將它解譯並還原為相同的狀態。然而,其中包含的 Permission 項目必須使用標準的形式。例如,CustomPermission 形式應如下所示:

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

IPermission 項目包含三個屬性:

  • class:包含由含有類別的組件名稱所明示的型別名稱

  • version:指定 XML 編碼的版本 (並非類別的組件版本)

  • Unrestricted:指定使用權限是否擁有不受限制的權限

所有的使用權限都必須使用 IPermission 的 XML 項目編碼,才可由一般語言 Runtime 安全性系統使用。

新版的使用權限物件應該和先前版本 XML 內保存的資訊回溯相容。版本標記 (Tag) 可以提供使用權限物件有關資料原始編碼的版本資訊。

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

其他資源

程式碼存取安全性