程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> 向WCF新增代碼訪問安全性,第2部分

向WCF新增代碼訪問安全性,第2部分

編輯:關於.NET

目錄

.NET Framework 3.5 中的宿主端 CAS

部分受信的服務

App Domain Host

實現 AppDomainHost

部分受信的宿主

結構化宿主端安全要求

實現結構化宿主要求

AppDomainHost 的其他方面

在 2008 年 4 月刊的這一專欄中,我討論了缺少對代碼訪問安全性 (CAS) 足夠支持的情形,以及向 Windows® Communication Foundation (WCF) 添 加合適 CAS 支持的動機。然後展示了如何在客戶端添加該支持,從而使部分受 信的客戶端可以調用 WCF 服務,並且它們均不會損害安全性或 WCF 編程模型( 如需四月專欄,請參閱 msdn.microsoft.com/magazine/cc500644)。

本期我將接著向您介紹部分受信的服務和宿主,幫您形成完整的印象。與客 戶端一樣,我講解的內容不僅包含解決方案的機制,還有它的形成方法和構思過 程。您還將了解到一些 WCF 和 Microsoft® .NET Framework 的高級編程技 術。

.NET Framework 3.5 中的宿主端 CAS

在 .NET Framework 3.5 中,WCF 僅允許部分受信的代碼通過 BasicHttpBinding、WSHttpBinding 和 WebHttpBinding 綁定托管服務,並且不 提供任何安全性或僅提供傳輸安全性。另外,對於 WSHttpBinding,消息安全性 、可靠的消息傳遞以及事務等都被禁用。所有啟用部分受信的綁定都必須使用文 本編碼。在部分受信模式下運行的服務無法使用其他功能(如診斷和性能計數器 )。

由綁定負責強制執行某些支持功能。每個非 HTTP 綁定都會主動要求服務宿 主的完全信任。適用 HTTP 綁定本身不需要完全信任;而是需要根據使用環境確 定所需的權限(如圖 1 所示)。

圖 1 適用 HTTP 綁定所需的宿主權限

方案 權限 Basic、Web 和 WS – 沒有安全性或傳輸安全性 執行和基礎結構安全權限;接受 URI 調用的 Web 權限。 前面提到的綁定,且在單獨程序集中包含內部服務類型 不受限制的反射。 前面提到的綁定,且包含通過身份驗證的調用 用於控制主體的安全權限。

所有適用 HTTP 綁定均需要執行權限和修改基礎結構的權限(帶有基礎結構 標記的安全權限),以及對其端點 URI 調用的接受權限(帶有 URI 接受標記的 Web 權限)。調用經過驗證後,適用 HTTP 綁定還需要用於控制線程主體的權限 (帶有主體控制標記的安全權限)。

這一點可以滿足,原因是在身份驗證之後,無論是何種綁定,WCF 都會安裝 一個新的主體,且其身份標識與調用期間提供的客戶端憑據相匹配。如果向宿主 構造函數提供的服務類型定義為另一程序集的內部類型,宿主還需要不受限制的 反射權限,以便能使用反射加載該類型。(需要基礎結構權限的決定有些莫明其 妙,因為並無對它的明顯需求。)

還需要考慮其他一些對配置的限制。例如,.config 文件不能包含任何對服 務端證書存儲區的引用,因為訪問證書存儲區會使 WCF 請求完全信任權限。管 理員必須使用工具(如 HttpConfig.exe)單獨配置這些證書。

僅依靠綁定請求宿主端權限的不足之處是:無論需要與否,都會隱式賦予托 管服務實例這些權限。例如,服務實例可控制主體或反射宿主上其他程序集的內 部類型。如果在確保服務權限為宿主代碼權限子集的同時,將綁定設計為請求其 權限並讓宿主能在一定程度上向服務授予不同權限,效果會更好。

理想情況下,您會希望能夠領略 WCF 的全部功能,從分布式事務到可靠調用 、各種安全性憑據類型、具有 TCP 和進程間通信(命名管道)綁定的 intranet (甚至是同一台計算機)應用程序;雙向回調、異步調用、診斷和跟蹤、檢測, 當然還有通過 Microsoft 消息隊列 (MSMQ) 實現的排隊調用。並且您希望所有 這一切都不會損害 CAS(即不必依賴完全信任權限實現上述功能)。

部分受信的服務

在 .NET Framework 3.0 中,要想用部分信任的形式執行服務,唯一方法是 明確授予服務履行功能必需的權限,隱式拒絕所有其他權限。通過 SecurityAction.PermitOnly 標記應用相應的權限屬性能夠做到這一點。請考慮 以下代碼中的服務:

[SecurityPermission(
 SecurityAction.PermitOnly,
 Execution = true)]
[UIPermission(SecurityAction.PermitOnly,
 Window =
  UIPermissionWindow.SafeTopLevelWindows)]
class MyService : IMyContract {
 public void MyMethod() {
  Form form = new TestForm();
  form.ShowDialog();
 }
}

服務需要執行權限(與所有受管代碼一樣),並且還必須具有顯示安全窗口 的權限。如果在一個類上堆放多個必需權限屬性,在運行時它會產生單個權限集 。

通過安裝專用的堆棧遍歷修飾符,.NET Framework 使用它僅授予這些權限並 主動拒絕所有其他權限。結果是,即使服務所在的程序集(以及應用程序域)向 其授予完全信任權限,也會拒絕所有其他權限。

當服務嘗試執行一個操作(如打開某個文件)時,由於文件 I/O 請求會遇到 將主動拒絕該權限的堆棧遍歷修飾符,所以會觸發安全異常。服務能做的就是在 虛擬沙箱中執行並顯示安全窗口。.NET Framework 將更改窗口標題並在出現的 窗體中顯示一個警告標記,告訴用戶應用程序為部分受信程序(如圖 2 所示) 。

圖 2 部分受信代碼顯示的窗口

您不是將權限指定為屬性,而是將它們列在權限集 XML 文件中並將該文件名 稱提供給 PermissionSetAttribute(如圖 3 所示)。

圖 3 將權限集文件用於部分受信服務

<!-- MyServicePermissions.xml -->
<PermissionSet class = "System.Security.PermissionSet">
 <IPermission
  class = "System.Security.Permissions.SecurityPermission"
  Flags = "Execution"
 />
 <IPermission
  class = "System.Security.Permissions.UIPermission"
  Window = "SafeTopLevelWindows"
 />
</PermissionSet>
[PermissionSet(SecurityAction.PermitOnly,File =
 "MyServicePermissions.xml")]
class MyService : IMyContract {
 public void MyMethod() {
  Form form = new TestForm();
  form.ShowDialog();
 }
}

請注意,權限集文件僅在編譯時使用,並不用於部署。編譯器將把允許的權 限融入類元數據,作為單個屬性使用。如果文件並不存在,構建將失敗。

App Domain Host

通過基於屬性的方法實現部分受信服務存在許多問題。首先,每次服務內容 發生更改(或它使用的任意下游類發生內容更改)時,均需要修改屬性堆棧或更 改文件。這樣會將服務耦合到這些類並增加維護成本。

其次,由於權限是服務定義的一部分,因而無法在托管環境中產生具有不同 權限的服務。無法賦予其更多或更少的權限。

第三,也是更為重要的一點,在實際中,不太可能出現大部分服務費力分析 其運行所必需的安全權限,並刻意降低其擁有的權限,以便采用最低權限運行。 如果有,那就是應由宿主考慮它加載的服務能勝任何種工作,而默認情況下宿主 是無法影響這一點的。WCF 的 ServiceHost 將托管完全信任的所有服務。

出於宿主以及服務自身保護的考慮,允許宿主授予其認為適合於服務的權限 是更好的選擇。為此,我編寫了圖 4 中定義的類 AppDomainHost。

public class AppDomainHost : IDisposable {
 //Create new app domain in full trust
 public AppDomainHost(Type serviceType,params Uri[] baseAddresses);
 public AppDomainHost(Type serviceType,string appDomainName,
  params Uri[] baseAddresses);
 //Create new app domain with specified permission set
 public AppDomainHost(Type serviceType,PermissionSet permissions,
  params Uri[] baseAddresses);
 public AppDomainHost(Type serviceType,PermissionSet permissions,
  string appDomainName,params Uri[] baseAddresses);
 //Additional constructors that take standard permission set,
 //permission set filename, and an existing app domain 
 public void Open();
 public void Close();
 public void Abort();
 //More members
}

類 AppDomainHost 的用法與 WCF 提供的 ServiceHost 一樣:

AppDomainHost host =
 new AppDomainHost(typeof(MyService));
host.Open();

不同之處在於 AppDomainHost 將把提供的服務類型放在一個新的應用程序域 中,而非放在其調用方的應用程序域中。新應用程序域名將默認為 "AppDomain Host for",後面帶有服務類型和一個新的 GUID。也可 為新應用程序域指定名稱:

AppDomainHost host =
 new AppDomainHost(typeof(MyService),"My App Domain");
host.Open();

默認情況下,以完全信任級別創建新的應用程序域。然而,將服務放在一個 單獨的應用程序域中是管理部分受信服務的關鍵所在。

AppDomainHost 允許為新應用程序域提供權限。例如,圖 5 展示了服務和僅 向服務授予正常運行所需權限的宿主。

class MyService : IMyContract {
 public void MyMethod() {
  Form form = new TestForm();
  form.ShowDialog();
 }
}
//Hosting code:
PermissionSet permissions =
 new PermissionSet(PermissionState.None);
permissions.AddPermission(new SecurityPermission(
 SecurityPermissionFlag.Execution));
permissions.AddPermission(new UIPermission(
 UIPermissionWindow.SafeTopLevelWindows));
AppDomainHost host =
 new AppDomainHost(typeof(MyService),permissions);
host.Open();

您也可使用權限集文件,與圖 3 中所示不同,此文件僅在運行時才會用到並 且可在部署後進行修改。請特別注意的是,還可以指定一個標准命名權限集。利 用部分受信服務的虛擬沙箱會影響可能使用的所有下游類,這些類是它能在沙箱 外通過任意技術(從 .NET Framework 1.0 到 WCF)調用的。

單個宿主進程可擁有 AppDomainHost 的多個實例,每個實例托管相同或不同 的服務類型,每個服務類型又具有任意的權限集,如圖 6 所示(使用與圖 5 中 相同的服務定義)。

圖 6 具有不同權限的相同服務類型

//Default is service with full trust
AppDomainHost host0 =
 new AppDomainHost(typeof(MyService),
 "Full Trust App Domain",
 new Uri("net.tcp://localhost:6000"));
host0.Open();
//With just enough permissions to do work
PermissionSet permissions1 =
 new PermissionSet(PermissionState.None);
permissions1.AddPermission(new SecurityPermission(
 SecurityPermissionFlag.Execution));
permissions1.AddPermission(new UIPermission(
 UIPermissionWindow.SafeTopLevelWindows));
AppDomainHost host1 =
 new AppDomainHost(typeof(MyService),permissions1,
 "Partial Trust App Domain",
 new Uri("net.tcp://localhost:6001"));
host1.Open();
//With not enough permissions to do work
PermissionSet permissions2 =
 new PermissionSet(PermissionState.None);
permissions2.AddPermission(new SecurityPermission(
 SecurityPermissionFlag.Execution));
AppDomainHost host2 =
 new AppDomainHost(typeof(MyService),permissions2,
 "Not enough permissions",new Uri ("net.tcp://localhost:6002"));
host2.Open();
//Using one of the named permission sets
AppDomainHost host3 =
 new AppDomainHost(typeof(MyService),
 StandardPermissionSet.Internet,
 "Named permission set",
 new Uri("net.tcp://localhost:6003"));
host3.Open();

實現 AppDomainHost

實現 AppDomainHost 分為兩個部分:創建一個新的應用程序域並注入一個服 務宿主實例,然後在部分信任環境下執行服務宿主(和服務實例)。為創建一個 服務宿主實例並在單獨的應用程序域中激活它,我編寫了圖 7 中所示的類 ServiceHostActivator。

圖 7 ServiceHostActivator

class ServiceHostActivator : MarshalByRefObject {
 ServiceHost m_Host;
 public void CreateHost(Type serviceType,Uri[] baseAddresses) {
  m_Host = new ServiceHost(serviceType,baseAddresses);
 }
 public void Open() {
  m_Host.Open();
 } 
 public void Close() {
  m_Host.Close();
 }
 public void Abort() {
  m_Host.Abort();
 }
 //Rest of the implementation
}

ServiceHostActivator 是 WCF 提供的標准 ServiceHost 實例的一個簡單包 裝。ServiceHostActivator 從 MarshalByRefObject 派生而來,因此 AppDomainHost 可跨越應用程序域邊界調用它。CreateHost 方法封裝構建一個 新 ServiceHost 實例。ServiceHostActivator 方法的剩余部分只是將遠程調用 轉發到底層宿主實例。

AppDomainHost 提供多個重載構造函數。這些構造函數均彼此調用(請參見 圖 8),甚至創建一個新的應用程序域並最終使用受保護的構造函數(它會使用 服務類型、新的應用程序域實例、新域的權限集以及基址)結束構造。

圖 8 實現 AppDomainHost

public class AppDomainHost : IDisposable {
 ServiceHostActivator m_ServiceHostActivator;
 public AppDomainHost(Type serviceType,
  params Uri[] baseAddresses) : 
  this(serviceType,"AppDomain Host for "+
  serviceType+" "+Guid.NewGuid(),
  baseAddresses) {
 }
 public AppDomainHost(Type serviceType,
  string appDomainName,
  params Uri[] baseAddresses) : this(serviceType,
  new PermissionSet(PermissionState.Unrestricted),
  appDomainName,baseAddresses) {
 }
 public AppDomainHost(Type serviceType,
 PermissionSet permissions,
 string appDomainName,
 params Uri[] baseAddresses) :
 this(serviceType,AppDomain.CreateDomain(appDomainName),
 permissions,baseAddresses) {
 }
 //More constructors
 protected AppDomainHost(Type serviceType,
  AppDomain appDomain,
  PermissionSet permissions,Uri[] baseAddresses) {
  string assemblyName = Assembly.GetAssembly(
   typeof(ServiceHostActivator)).FullName;
  m_ServiceHostActivator = appDomain.CreateInstanceAndUnwrap(
   assemblyName,typeof(ServiceHostActivator).ToString()) as
   ServiceHostActivator;
  CodeAccessSecurityHelper.SetPermissionsSet (appDomain,permissions);
  m_ServiceHostActivator.CreateHost(serviceType,baseAddresses);
 }
 public void Open() {
  m_ServiceHostActivator.Open();
 }
 public void Close() {
  m_ServiceHostActivator.Close();
 }
 public void Abort() {
  m_ServiceHostActivator.Abort();
 }
 void IDisposable.Dispose() {
  Close();
 }
}

AppDomainHost 的受保護構造函數使用 .NET 遠程機制向新應用程序域注入 一個 ServiceHostActivator 實例,並且最後向其注入存儲在 m_ServiceHostActivator 成員中的遠程機制代理。

默認情況下,以完全信任級別創建新的應用程序域。AppDomainHost 使用 CodeAccessSecurityHelper 類的 SetPermissionsSet 方法在新的應用程序域中 安裝一個新的 CAS 策略 — 從而僅授予提供的權限並拒絕其他權限:

public static class CodeAccessSecurityHelper {
 public static void SetPermissionsSet(
  AppDomain appDomain,
  PermissionSet permissions) {
  PolicyLevel policy = PolicyLevel.CreateAppDomainLevel();
  policy.RootCodeGroup.PolicyStatement =
   new PolicyStatement(permissions);
  appDomain.SetAppDomainPolicy(policy);
 }
 //More members
}

它與在應用程序域級創建一個新的安全策略並調用 AppDomain 類的 SetAppDomainPolicy 方法一樣簡單:

public sealed class AppDomain :
 MarshalByRefObject,... {
 public void SetAppDomainPolicy(
  PolicyLevel domainPolicy);
 //More members
}

順便說一下,ClickOnce 使用類似技術針對部署了 ClickOnce 的應用程序來 強制執行部分信任。

如果調用 AppDomainHost 的其他方法(如 Open 或 Close),將使用 ServiceHostActivator 的代理來調用其他應用程序域並讓其打開或關閉宿主實 例。由於服務實例將在打開宿主的應用程序域中執行,因此服務執行時還會使用 應用程序域的安全策略。

部分受信的宿主

迄今為止,實現部分受信服務的方法是有前提的,即擁有代碼且它使用以完 全信任權限運行的 AppDomainHost。原因是除圖 1 中列出的托管方案以外, ServiceHost 和綁定都需要請求完全信任。

但如果啟動宿主的僅是部分受信的代碼,那又會如何呢?可將 AppDomainHost 和 ServiceHostActivator 放入完全受信的程序集中,允許有部 分受信的調用方並將它們均聲明為完全信任:

[PermissionSet(SecurityAction.Assert,Unrestricted = true)]
public class AppDomainHost : IDisposable
{...}
[PermissionSet(SecurityAction.Assert,Unrestricted = true)]
class ServiceHostActivator : MarshalByRefObject
{...}

盡管此方法很有效,但它避開了 CAS 並禁用了至關重要的安全機制,並且這 樣會產生兩個安全性問題。首先,不應假設打開宿主的代碼有權接受針對傳輸通 道的調用或能自由參與 WCF 活動(如分發事務)。其次,通過聲明完全信任且 禁止堆棧遍歷,啟動宿主的部分受信代碼實際可創建一個具有更高權限的服務, 將其用於不良企圖。例如,托管代碼可能並無文件 I/O 權限,但它可使用 AppDomainHost 接受對具有文件 I/O 權限的服務的調用。

解決方案很簡單:AppDomainHost 和 ServiceHostActivator 不應使用完全 信任的空白聲明。而是應在必要時僅在本地聲明,然後還原成現有權限。此外, AppDomainHost 應能質詢使用它的代碼,請求適當的托管權限(如接受調用)。 它還應確認托管代碼至少已被授予運行服務所需的權限。從而防止部分信任的受 限代碼以更大的權限使用在單獨應用程序域中托管的服務。最終產生出結構化宿 主端安全要求。

結構化宿主端安全要求

圖 9 顯示了適用於部分信任的調用方且經過改寫的 ServiceHostActivator 。ServiceHostActivator 的 CreateHost 方法無法聲明完全信任,因為這樣將 使其無法請求調用代碼的適當宿主權限。它通過編程方式使用 CodeAccessSecurityHelper 創建完全信任權限集並加以聲明,然後繼續創建宿 主。當 WCF 請求完全信任時,聲明可防止該請求在調用堆棧中上移。

圖 9 改寫後的 ServiceHostActivator

class ServiceHostActivator : MarshalByRefObject {
 public void CreateHost(Type serviceType,Uri[] baseAddresses) {
  CodeAccessSecurityHelper.PermissionSetFromStandardSet(
  StandardPermissionSet.FullTrust).Assert();
  m_Host = new ServiceHost(serviceType,baseAddresses);
  PermissionSet.RevertAssert();
  m_Host.DemandHostPermissions();
 }
 //Behavior demands happen here, must assert
 [PermissionSet(SecurityAction.Assert,Unrestricted = true)]
 public void Open() {
  m_Host.Open();
 } 
 ...
}

創建宿主後,CreateHost 明確還原聲明。然後,CreateHost 針對剛創建的 宿主實例調用 DemandHostPermissions(CodeAccessSecurityHelper 的擴展幫 助程序方法)以請求托管權限。DemandHostPermissions 檢查宿主對象並請求適 當的權限。

例如,如果宿主支持 TCP 端點,則 DemandHostPermissions 會請求執行權 限和接受對端點 URI 的 TCP 調用的權限。如果通過 TCP 使用可靠的消息傳遞 ,DemandHostPermissions 會請求控制策略權限。還可能有許多其他請求,如圖 10 所示。

方案 權限 TCP 執行安全權限、接受對 URI 的 TCP 調用的套接字權限。 IPC 執行、控制策略以及控制證明等安全權限。 MSMQ 執行安全權限、從隊列讀取的 MSMQ 權限。 WS、WS-Dual、Basic、Web 執行安全權限和接受對 URI 的調用的 Web 權限。 基於 TCP 的 RM 用於控制策略的安全權限。 通過身份驗證的調用 用於控制主體的安全權限。 事務傳播 不受限制的分發事務權限 具有消息安全性的用戶名憑據、具有驗證的證書憑據以及服務 證書 用於枚舉存儲區、打開存儲區以及枚舉證書的存儲區權限 診斷跟蹤 用於讀取 COMPUTERNAME 的環境權限、用於路徑發現、附加和 寫入日志文件的文件 I/O 權限。 WCF 服務性能計數器 向服務計數器、端點計數器和操作計數器寫入的性能計數器權 限。 所有 WCF 性能計數器 向服務計數器、端點計數器、操作計數器和宿主計數器寫入的 性能計數器權限。 ASP.NET 提供程序 最小 ASP.NET 托管權限。

使用 IPC 綁定時需要用於控制策略和證明的權限。使用 MSMQ 綁定時需要從 端點隊列讀取的權限。使用任何 HTTP 綁定時都需要能夠接受對端點地址的調用 。如果綁定使用通過身份驗證的調用,DemandHostPermissions 會請求控制主體 權限。

如果使用識別事務的綁定,同時啟用了事務流並允許(或強制)對事務流的 端點約定至少執行一個操作,則需要不受限制的分發事務權限。

只要訪問證書存儲區(如通過消息安全性、客戶端證書驗證或使用服務證書 來保護消息),就需要存儲區枚舉權限以打開存儲區並枚舉證書。

如果服務執行診斷,DemandHostPermissions 將需要訪問計算機名稱環境變 量以及該文件的文件 I/O 權限。如果宿主使用 WCF 性能計數器, DemandHostPermissions 會請求在報告級寫入計數器的權限。

如果宿主依賴於 ASP.NET 提供程序實現調用方身份驗證或角色成員身份, DemandHostPermissions 將需要最小的 ASP.NET 托管權限(所有提供程序均需 要該權限)。在通過 WS-Dual 綁定回調時,綁定本身將需要 Web 權限來連接該 回調端點,因此在啟動宿主時 AppDomainHost 不必顯式請求此權限。

實現結構化宿主請求

圖 11 顯示了 DemandHostPermissions 的部分實現,它首先執行特定於端點 的要求。它遍歷服務的端點集合,並且對於每個端點,它均需要單獨的連接性、 安全性和事務權限。

圖 11 實現 DemandHostPermissions

public static class CodeAccessSecurityHelper {
 internal static void DemandHostPermissions(this ServiceHost host) {
  foreach(ServiceEndpoint endpoint in host.Description.Endpoints) {
   DemandHostConnectionPermissions(endpoint);
   DemandHostSecurityPermissions(endpoint);
   using(TransactionScope scope = new TransactionScope()) {
    DemandTransactionPermissions(endpoint);
   }
  }
  DemandHostStorePermissions(host);
  DemandPerformanceCounterPermissions();
  DemandTracingPermissions();
  DemanAspNetProvidersPermissions(host);
 }
 internal static void DemandHostConnectionPermissions(
  ServiceEndpoint endpoint) {
  PermissionSet connectionSet =
   new PermissionSet(PermissionState.None);
  if(endpoint.Binding is NetTcpBinding) {
   connectionSet.AddPermission(new SocketPermission(
    NetworkAccess.Accept, TransportType.Tcp,
    endpoint.Address.Uri.Host,endpoint.Address.Uri.Port));
  }
  /* Checking the other bindings */
  connectionSet.Demand();
 }
 static void DemanAspNetProvidersPermissions(ServiceHost host) {
  bool demand = false;
  foreach(IServiceBehavior behavior in host.Description.Behaviors) {
   if(behavior is ServiceCredentials) {
    ServiceCredentials credentialsBehavior =
     behavior as ServiceCredentials;
    if(credentialsBehavior.UserNameAuthentication.
     UserNamePasswordValidationMode ==
     UserNamePasswordValidationMode.MembershipProvider) {
     demand = true;
     break;
    }
   }
   if(behavior is ServiceAuthorizationBehavior) {
    ServiceAuthorizationBehavior serviceAuthorization =
     behavior as ServiceAuthorizationBehavior;
    if(serviceAuthorization.PrincipalPermissionMode ==
     PrincipalPermissionMode.UseAspNetRoles &&
     Roles.Enabled) {
     demand = true;
     break;
    }
   }
  }
  if(demand) {
   IPermission permission =
    new AspNetHostingPermission(
    AspNetHostingPermissionLevel.Minimal);
   permission.Demand();
  }
 }
 //Rest of the implementation
}

對於事務權限請求,它使用事務范圍創建一個臨時的環境事務。從而可使用 與客戶端相同的方法,該方法在調用時根據是否存在環境事務來請求權限。

端點進行請求之後,DemandHostPermissions 請求服務宿主配置產生的權限 ,具體說來是證書存儲區訪問權限、性能計數器權限、跟蹤權限和 ASP.NET 提 供程序權限。例如,要請求 ASP.NET 提供程序權限,它獲取服務行為集合並查 看宿主的服務憑據行為是否在使用成員身份提供程序,或宿主的服務授權行為是 否在使用角色提供程序,如果是則請求 ASP.NET 托管權限。

還需要改寫 AppDomainHost 以在部分信任環境中支持結構化請求,如下所示 :

[SecurityPermission(
 SecurityAction.Assert,ControlAppDomain = true)]
[ReflectionPermission(
 SecurityAction.Assert,Unrestricted = true)]
public class AppDomainHost : IDisposable {
 protected AppDomainHost(Type serviceType,
  AppDomain appDomain,
  PermissionSet permissions,
  params Uri[] baseAddresses) {
  //Cannot grant service permissions
  // the host does not have
  permissions.Demand();
  //Rest of constructor
  }
}

由於 AppDomainHost 創建了一個新的應用程序域,因此要聲明對此應用程序 域的控制權限。因為它使用反射在其他應用程序域中注入宿主,因此要聲明不受 限制的反射權限。最重要的是,在新的應用程序域中創建服務宿主之前,AppDomainHost 會為調用它的代碼的服務請求所需權限。從而確保部分受信的代 碼僅可啟動並托管作用范圍與調用代碼相同的服務。

AppDomainHost 的其他方面

盡管 AppDomainHost 並不支持 ICommunicationObject,但它提供了事件模 型和狀態機管理。AppDomainHost 還將一些靜態變量從調用應用程序域復制到自 己創建的新應用程序域中。具體來說,它使用 ServiceHostActivator 將 ASP.NET 提供程序應用程序名稱復制到其他應用程序域。AppDomainHost 臨時聲 明 ASP.NET 托管權限、訪問提供程序、復制成員身份和角色應用程序名稱的值 ,然後還原聲明。

Juval Lowy 是 IDesign 的一名軟件架構師,該公司提供 WCF 培訓和體系結 構咨詢。他最近編寫了一本名為《Programming WCF Services》的新書。另外, 他還是 Microsoft 硅谷地區的區域總監。您可以通過 www.idesign.net 與 Juval 聯系。

本文配套源碼

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved