利用EntLib授權機制實現對ASP.NET頁面的自動授權


ASP.NET默認采用UrlAuthorizationModuleFileAuthorizationModule分別實現針對請求地址和物理文件的授權,但是在很多情況下我們需要額外的授權方式。Entlib提供了一種基於表達式的授權方式,它允許我們以一個表達式的方式來定義授權的規則。在新的項目中我們希望利用EntLib的授權框架來實現針對ASP.NET頁面的自動授權,本文描述的解決方案是我剛剛想到的,希望廣大網友朋友們幫助評估一下。[源代碼從這里下載]

目錄
一、實例演示
二、AuthorizationFilterAttribute
三、AuthorizeAttribute
四、PageBase

一、實例演示

我們先來作一個簡單的實例演示。如下所示的EntLib安全模塊的配置,如果讀者對此不了解也沒有關系,在這里我們只需要關注定義其中的一個授權規則(Authorization Rule):“I:Foo OR R:Admin”。這是一個邏輯表達式,前綴I:和R:分別表示用戶名(Identity)和角色(Role),整個表達式表示的授權邏輯是:“帳號為Foo的用戶和所有具有Admin角色的用戶”有權限方法與此表達式關聯的操作或者資源。配置還定義了該授權規則的名稱“FooOrAdmin”。

   1: <configuration>
   2:   <configSections>
   3:     <section name="securityConfiguration" 
   4:              type="Microsoft.Practices.EnterpriseLibrary.Security.Configuration.SecuritySettings, 
   5:                    Microsoft.Practices.EnterpriseLibrary.Security"/>
   6:   </configSections>
   7:   <securityConfiguration defaultAuthorizationInstance="Authorization Rule Provider">
   8:     <authorizationProviders>
   9:       <add name="Authorization Rule Provider"
  10:            type="Microsoft.Practices.EnterpriseLibrary.Security.AuthorizationRuleProvider, 
  11:                  Microsoft.Practices.EnterpriseLibrary.Security">
  12:         <rules>
  13:           <add expression="I:Foo OR R:Admin" name="FooOrAdmin" />
  14:         </rules>
  15:       </add>
  16:     </authorizationProviders>
  17:   </securityConfiguration>
  18: </configuration>

我們添加一個需要授權的Web頁面(Default.aspx),並且使用上面定義的表達式來作為該頁面的授權規則,我們通過自定義的AuthorizeAttribute特性實現兩者之間的關聯(該特性構造函數中指定的字符串正是配置的授權規則名稱)。除此之外,Web頁面對應的類型繼承自我們自定義的基類PageBase。

   1: [Authorize("FooOrAdmin")]
   2: public partial class Default : PageBase
   3: {   
   4: }

我們隨后添加一個登錄頁面,具體的實現就不再這里一一介紹了。為了模擬不同的登錄用戶具有不同的權限,我們通過注冊HttpApplication的AuthenticateRequest事件來對當前Principal進行定制。具體的定義如下所示:如果用戶名為Bar,我們讓當前的Principal具有Admin角色,對於其他帳號的登錄用戶,角色列表為空。

   1: public class Global : System.Web.HttpApplication
   2: {
   3:     protected void Application_AuthenticateRequest(object sender, EventArgs e)
   4:     {
   5:         if (null == HttpContext.Current.User || !HttpContext.Current.User.Identity.IsAuthenticated)
   6:         {
   7:             return;
   8:         }
   9:  
  10:         IIdentity identity = new GenericIdentity(HttpContext.Current.User.Identity.Name);
  11:         string[] roles = null;
  12:         if (identity.Name.ToLower() == "bar")
  13:         {
  14:             roles = new string[] { "Admin" };
  15:         }
  16:         HttpContext.Current.User = new GenericPrincipal(identity, roles);
  17:     }
  18: }

由於頁面Default.aspx與配置名稱為FooOrAdmin的授權規則進行了關聯,根絕授權規則表達式定義和針對不同用戶的角色列表,意味着當我們以賬戶Foo和Bar登錄后才能訪問該頁面,“自動化授權”可以通過下圖得到證實:當前用戶為Foo和Bar時,頁面得以正常顯示;而當我們以Baz的身份登錄后,顯示“Access denied…”。

二、AuthorizationFilterAttribute

這里我吸取了ASP.NET MVC基於AuthorizationFilter的授權方式,不同的是AuthorizationFilter在ASP.NET MVC中以特性的方式應用到Controller類型和Action方法上,這里我們則將它應用到Web頁面對應的類上。AuthorizationFilterAttribute作為授權篩選器特性的基類定義如下,由於多個特性可以同時應用到同一個類型上,它們的執行順序通過屬性Order來控制。具體的授權判斷以及對非授權請求的處理定義在方法OnAuthorization方法上。

   1: [AttributeUsage( AttributeTargets.Class, AllowMultiple = true)]
   2: public abstract class AuthorizationFilterAttribute:Attribute
   3: {
   4:     public int Order { get; set; }
   5:     public abstract bool OnAuthorization(AuthorizationContext context);        
   6: }
   7:  
   8: public class AuthorizationContext
   9: {
  10:     public HttpContext  HttpContext { get; private set; }
  11:     public bool         UnAuthorizedRequestHandled { get; set; }
  12:  
  13:     public AuthorizationContext(HttpContext httpContext)
  14:     {
  15:         this.HttpContext = httpContext;
  16:     }
  17: }

OnAuthorization方法返回值代表的是真否授權的判斷,它具有一個類型為AuthorizationContext參數。AuthorizationContext是對HttpContext對象的封裝,屬性UnAuthorizedRequestHandled 表示是否完成了針對非授權請求的處理。如果多個AuthorizationFilterAttribute應用到同一個類型上,如果前面執行的AuthorizationFilterAttribute將傳入的AuthorizationContext的這個屬性設置為True,后續的將不在執行。

三、AuthorizeAttribute

基於EntLib的授權通過AuthorizeAttribute來實現。如下面的代碼片斷所示,AuthorizeAttribute 直接繼承自AuthorizationFilterAttribute,代表授權規則配置名稱的屬性AuthorizationRule 在構造函數中被初始化。在實現的OnAuthorization我們按照Entlib授權框架的編程模式判斷當前Principal是否具有針對指定授權規則的權限,對於非授權請求我們直接調用HandleUnauthorizedRequest方法進行處理。具體的處理邏輯很簡單:直接相應一段文字“Access denied…”(正是上面截圖中顯示的文字)。出於可擴展的考慮,我們將此方法定義成受保護的虛方法。

   1: [AttributeUsage( AttributeTargets.Class, AllowMultiple = true)]
   2: public class AuthorizeAttribute : AuthorizationFilterAttribute
   3: {
   4:     public string AuthorizationRule { get; private set; }
   5:     public AuthorizeAttribute(string authorizationRule)
   6:     {
   7:         Guard.ArgumentNotNullOrEmpty(authorizationRule, "authorizationRule");
   8:         this.AuthorizationRule = authorizationRule;
   9:     }
  10:  
  11:     public override bool OnAuthorization(AuthorizationContext context)
  12:     {
  13:         IAuthorizationProvider authorizationProvider = AuthorizationFactory.GetAuthorizationProvider();
  14:         if (authorizationProvider.Authorize(context.HttpContext.User, this.AuthorizationRule))
  15:         {
  16:             return true;
  17:         }
  18:         this.HandleUnauthorizedRequest(context);
  19:         return false;
  20:     }
  21:  
  22:     protected virtual void HandleUnauthorizedRequest(AuthorizationContext context)
  23:     {
  24:         context.HttpContext.Response.Write(context.HttpContext.User.Identity.Name + ": Access denied...");
  25:     }
  26: }

四、PageBase

我們知道針對一個ASP.NET 資源的請求最后大都通過一個對應的HttpHandler來處理,這個授權解決方案的基本思路就是通過自定義HttpHandler實現自動化授權檢驗。Page類型是我們最為熟悉的HttpHandler,為此我們定義了如下一個繼承自它的類型PageBase。如下面的代碼片斷所示,在重寫的ProcessRequest方法中實現了對應用在當前類型上的AuthorizationFilterAttribute特性的解析和執行,進而提供了對授權的實現。

   1: public abstract class PageBase: Page
   2: {
   3:     public override void ProcessRequest(HttpContext context)
   4:     {
   5:         var filterAttributes = this.GetType().GetCustomAttributes(true)
   6:                                 .OfType<AuthorizationFilterAttribute>()
   7:                                 .OrderBy(attribute => attribute.Order);
   8:         AuthorizationContext authorizationContext = new AuthorizationContext(context);
   9:         bool isAuthorized = true;
  10:         foreach (AuthorizationFilterAttribute attribute in filterAttributes)
  11:         {
  12:             isAuthorized = attribute.OnAuthorization(authorizationContext);
  13:             if (authorizationContext.UnAuthorizedRequestHandled)
  14:             {
  15:                 break;
  16:             }
  17:         }
  18:  
  19:         if (isAuthorized)
  20:         {
  21:             base.ProcessRequest(context);
  22:         }
  23:     }    
  24: }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM