[WCF許可權控制]利用WCF自定義授權模式提供當前Principal[原理篇]

行者武松發表於2017-10-26

在《通過擴充套件自行實現服務授權》一文中,我通過自定義CallContextInitializer的方式在操作方法之前之前根據認證使用者設定了當前執行緒的安全主體,從而實現授權的目的。實際上,WCF的安全體系本就提供相應的擴充套件,使你能夠自由地實現安全主體的提供方式。具體來說,安全主體的提供可以通過自定AuthorizationPolicy或者ServiceAuthorizationManager來實現。

一、AuthorizationPolicy

在WCF安全應用程式設計介面中,所有的AuthorizationPolicy實現了IAuthorizationPolicy介面。如下面的程式碼所示,IAuthorizationPolicy繼承自IAuthorizationComponent介面,本身具有一個ClaimSet型別的Issuer屬性和一個Evaluate方法。關於ClaimSet,我們會在後續的部分繼續介紹,這裡我們只需要關注Evaluate方法。該方法的第一個引數的型別為System.IdentityModel.Policy.EvaluationContext,它具有一個字典型別的只讀屬性Properties。

   1: public interface IAuthorizationPolicy : IAuthorizationComponent
   2: {
   3:     bool Evaluate(EvaluationContext evaluationContext, ref object state);
   4:     ClaimSet Issuer { get; }
   5: }
   6: public abstract class EvaluationContext
   7: {
   8:     //其他成員
   9:     public abstract IDictionary<string, object> Properties { get; }
  10: }

如果我們需要通過自定義的方式來提供安全主體,我們只需要通過實現IAuthorizationPolicy介面建立自定義的AuthorizationPolicy,並在Evaluate方法中將建立安全主體物件新增到EvaluationContext的Properties字典中即可。在該字典中,用於存放安全主體條目對應的鍵值為“Principal”。

   1: Public class CustomAuthorizationPolicy:IAuthorizationPolicy
   2: {
   3:    //其他成員
   4:    bool Evaluate(EvaluationContext evaluationContext, ref object state)
   5:    {
   6:      //其他操作
   7:       evaluationContext. Properties[“Principal”] = customPrincipal;
   8:       return true;
   9:    }
  10: }

那麼自定義的AuthorizationPolicy通過怎樣的方式被應用到WCF的授權執行時呢?這還是要藉助於我們已經很熟悉的服務行為ServiceAuthorizationBehavior。如下面給出的程式碼片斷所示,ServiceAuthorizationBehavior具有一個型別為ReadOnlyCollection<IAuthorizationPolicy>
的ExternalAuthorizationPolicies屬性,表示自定義AuthorizationPolicy的集合。

   1: public sealed class ServiceAuthorizationBehavior : IServiceBehavior
   2: {
   3:     //其他成員
   4:     public ReadOnlyCollection<IAuthorizationPolicy> ExternalAuthorizationPolicies { get; set; }
   5: }

你可以通過程式設計的方式將自定義的AuthorizationPolicy新增到ServiceAuthorizationBehavior的ExternalAuthorizationPolicies集合中,也可以通過配置指定自定義AuthorizationPolicy的型別。如下面給出的配置片斷所示,ServiceAuthorizationBehavior的ExternalAuthorizationPolicies集合對應的配置節點為<serviceAuthorization>/<authorizationPolicies>。

   1: <configuration>
   2:   <system.serviceModel>
   3:     <behaviors>
   4:       <serviceBehaviors>
   5:         <behavior  name="useCustomAuthorization">         
   6:           <serviceAuthorization principalPermissionMode="Custom">
   7:             <authorizationPolicies >
   8:               <add policyType="AuthorizationPolicyType1" />
   9:               <add policyType="AuthorizationPolicyType2" />
  10:               ...
  11:             </authorizationPolicies>
  12:           </serviceAuthorization>
  13:           <serviceDebug includeExceptionDetailInFaults="true"/>
  14:         </behavior>
  15:       </serviceBehaviors>
  16:     </behaviors>
  17:   </system.serviceModel>
  18: </configuration>

二、ServiceAuthorizationManager

在ServiceAuthorizationBehavior選擇Custom安全主體許可權模式的情況下,除了自定義AuthorizationPolicy,你還可以通過自定義ServiceAuthorizationManager來提供當前的安全主體。下面給出了ServiceAuthorizationManager的定義,從中我們可以看出它具有兩個CheckAccess方法用於實現授權。方法的返回值表示當前請求的服務操作是否被授權指定。實際上最終的授權判斷實現在受保護方法CheckAccessCore中,並且在ServiceAuthorizationManager中該方法直接返回True。

   1: public class ServiceAuthorizationManager
   2: {
   3:     //其他成員
   4:     public virtual bool CheckAccess(OperationContext operationContext);
   5:     public virtual bool CheckAccess(OperationContext operationContext, ref Message message);
   6:     protected virtual bool CheckAccessCore(OperationContext operationContext);
   7: }

當ServiceAuthorizationBehavior的PrincipalPermissionMode被設定成Custom的情況下,被設定的當前安全主體實際上是通過當前服務安全上下文(ServiceSecurityContext)獲取的。具體來說,ServiceSecurityContext具有一個表示授權資訊的AuthorizationContext物件。和EvaluationContext一樣,AuthorizationContext也具有一個字典型別的Properties屬性。實際上,通過AuthorizationPolicy新增到EvaluationContext中的屬性,最終都會被轉移到當前AuthorizationContext的Properties屬性中。

   1: public class ServiceSecurityContext
   2: {
   3:     //其他成員
   4:     public AuthorizationContext AuthorizationContext { get; }
   5: }
   6: public abstract class AuthorizationContext : IAuthorizationComponent
   7: {  
   8:     //其他成員
   9:     public abstract IDictionary<string, object> Properties { get; }
  10: }

所以只要我們能夠在WCF從當前AuthorizationContext獲取安全主體之前對其進行初始化,整個基於安全主體的授權體系就能正常運作,而這個工作可以通過自定義ServiceAuthorizationManager來實現。一般來講,我們只需通過繼承ServiceAuthorizationManager,重寫虛方法CheckAccessCore進行安全主體的初始化。

   1: public class CustomServiceAuthorizationManager : ServiceAuthorizationManager
   2: {
   3:     protected override bool CheckAccessCore(OperationContext operationContext)
   4: {
   5:     //其他操作
   6:         AuthorizationContext authorizationContext = operationContext.ServiceSecurityContext.AuthorizationContext;
   7:         authorizationContext.Properties["Principal"] = customPrincipal;
   8:         return true;
   9:     }
  10: }

自定義的ServiceAuthorizationManager最終還是通過ServiceAuthorizationBehavior這個服務行為應用到WCF授權框架體系中。如下面給出的程式碼片斷所示,在ServiceAuthorizationBehavior中依然具有相應屬性定義的。而在ServiceAuthorizationBehavior的配置節中,ServiceAuthorizationManager對應的配置屬性為serviceAuthorizationManager,你可以通過該配置屬性將設定自定義ServiceAuthorizationManager的型別。

   1: public sealed class ServiceAuthorizationBehavior: IServiceBehavior
   2: {
   3:     //其他成員
   4:     public ServiceAuthorizationManager ServiceAuthorizationManager { get; set; }
   5: }

如果兩種預設的安全主體許可權模式(UseWindowsGroup和UseAspNetRoles)不能滿足你的要求,你需要自定義安全主體提供方式,自定義AuthorizationPolicy或者ServiceAuthorizationManager不失為一個很好的解決方案。為了讓你對此有個深刻的認識,在《下篇》中我們提供一個完整的例項。

[WCF許可權控制]利用WCF自定義授權模式提供當前安全主體[原理篇]

[WCF許可權控制]利用WCF自定義授權模式提供當前安全主體[例項篇]

作者:蔣金楠
微信公眾賬號:大內老A
微博:www.weibo.com/artech
如果你想及時得到個人撰寫文章以及著作的訊息推送,或者想看看個人推薦的技術資料,可以掃描左邊二維碼(或者長按識別二維碼)關注個人公眾號(原來公眾帳號蔣金楠的自媒體將會停用)。
本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段宣告,且在文章頁面明顯位置給出原文連線,否則保留追究法律責任的權利。


相關文章