[.NET 基於角色安全性驗證] 之四:ASP.NET 2.0 成員資格和角色管理授權

來源:互聯網
上載者:User

從嚴格意義上來說,ASP.NET 2.0 的成員資格、角色管理授權和 .NET 角色安全性沒有多大關係。只不過,Microsoft 替我們完成了一些原本需要我們自己進行的工作而已。

在這兩種新的技術中使用的"提供者模型"倒是值得我們好好學習一下,因為這個 IoC 概念非常相似。

成員資格

成員資格提供了通用的使用者管理功能,諸如註冊、登入、找回密碼等,加上與之配套的可視化控制項,我們“幾乎”不用在編寫額外的代碼就可以工作。實際上真是如此嗎?MemebershipUser 屬性太少,顯然不大適合我們的商業應用;註冊和登入控制項有缺乏驗證碼,缺乏安全性;…… 當然我們還可以使用自訂驗證和提供者,不過如此一來還不如自己參考"提供者模型"開發一套呢,畢竟獨立的 Passport 才是我們所需要的,更不要說和既有系統進行整合了,總之 ASP.NET 提供的這個新功能,食之無味,棄之可惜。有關成員資格和角色管理的使用不是本文的重點,詳情可參考 MSDN 文檔。

成員資格由 Membership、MembershipUser、MembershipProvider 組成,Membership 是個靜態類,為使用者提供了大量使用者相關的操作方法,MembershipUser 則是使用者實體類,除了使用者屬性外也有一些使用者自身的操作方法,而 MembershipProvider 自然就是提供者的基礎抽象類別了,它規範了提供者的介面。

我們分析一下 Membership 代碼(局部代碼),看看如何擷取真實的目標提供者對象的。其實過程也很簡單,讀取配置擷取類型資訊,然後用反射建立目標提供者對象執行個體。

System.System.Web.Security.Membership

// 我們從 ValidateUser 方法入手。
public static bool ValidateUser(string username, string password)
{
   // 通過 Provider 屬性擷取提供者對象
   return Membership.Provider.ValidateUser(username, password);
}

public static MembershipProvider Provider
{
   get
   {
     // 應該是通過 Initialize() 方法擷取,並賦值給 s_Provider 變數的。
     Membership.Initialize();
     return Membership.s_Provider;
   }
}

private static void Initialize()
{
   // 從設定檔中讀取配置資訊
   RuntimeConfig config1 = RuntimeConfig.GetAppConfig();
   MembershipSection section1 = config1.Membership;

   Membership.s_Providers = new MembershipProviderCollection();

   // 使用 ProvidersHelper.InstantiateProviders 方法從配置資訊中讀取設定。
   ProvidersHelper.InstantiateProviders(section1.Providers, Membership.s_Providers, typeof(MembershipProvider));

   // 將預設提供者對象賦值給 s_Provider 變數。
   Membership.s_Provider = Membership.s_Providers[section1.DefaultProvider];
   Membership.s_Initialized = true;
}

public static void ProvidersHelper.InstantiateProviders(ProviderSettingsCollection configProviders, ProviderCollection providers, Type providerType)
{
   // 迴圈讀取配置資訊,並建立提供者對象。
   foreach (ProviderSettings settings1 in configProviders)
   {
     providers.Add(ProvidersHelper.InstantiateProvider(settings1, providerType));
   }
}

public static ProviderBase ProvidersHelper.InstantiateProvider(ProviderSettings providerSettings, Type providerType)
{
   ProviderBase base1 = null;
   try
   {
     // 調用 HttpRuntime.CreatePublicInstance 建立提供者對象。
     base1 = (ProviderBase)HttpRuntime.CreatePublicInstance(type1);
   }
   catch (Exception exception1)
   {
   }
   return base1;
}

internal static object HttpRuntime.CreatePublicInstance(Type type)
{
   // 利用反射建立對象
   return Activator.CreateInstance(type);
}

下面我們分析一下 Login 控制項的源碼,我們會發現其內部不過是自動調用 Membership 和 MembershipProvider 進行操作而已。

System.Web.UI.WebControls.Login

private void AttemptLogin()
{
   if ((this.Page == null) || this.Page.IsValid)
   {
     LoginCancelEventArgs args1 = new LoginCancelEventArgs();
     this.OnLoggingIn(args1);
     if (!args1.Cancel)
     {
       AuthenticateEventArgs args2 = new AuthenticateEventArgs();

       // 調用核心代碼
       this.OnAuthenticate(args2);

       // 看到了什嗎?標準的身分識別驗證代碼。詳情可以查看上一篇Blog。
       if (args2.Authenticated)
       {
         FormsAuthentication.SetAuthCookie(this.UserNameInternal, this.RememberMeSet);
         this.OnLoggedIn(EventArgs.Empty);
         this.Page.Response.Redirect(this.GetRedirectUrl(), false);
       }
       else
       {
         this.OnLoginError(EventArgs.Empty);
         if (this.FailureAction == LoginFailureAction.RedirectToLoginPage)
         {
           FormsAuthentication.RedirectToLoginPage("loginfailure=1");
         }
         ITextControl control1 = (ITextControl)this.TemplateContainer.FailureTextLabel;
         if (control1 != null)
         {
           control1.Text = this.FailureText;
         }
       }
     }
   }
}

protected virtual void OnAuthenticate(AuthenticateEventArgs e)
{
   AuthenticateEventHandler handler1 = (AuthenticateEventHandler)base.Events[Login.EventAuthenticate];
   if (handler1 != null)
   {
     // 使用者使用了自訂驗證服務
     handler1(this, e);
   }
   else
   {
     // 使用成員資格提供者
     this.AuthenticateUsingMembershipProvider(e);
   }
}

private void AuthenticateUsingMembershipProvider(AuthenticateEventArgs e)
{
   // 使用 LoginUtil.GetProvider 擷取成員資格提供者對象,並調用其 ValidateUser 進行身分識別驗證。
   e.Authenticated = LoginUtil.GetProvider(this.MembershipProvider).ValidateUser(this.UserNameInternal, this.PasswordInternal);
}

internal static LoginUtil.MembershipProvider GetProvider(string providerName)
{
   if (string.IsNullOrEmpty(providerName))
   {
     return Membership.Provider;
   }

   // 調用 Membership 相關屬性,擷取提供者對象。
   MembershipProvider provider1 = Membership.Providers[providerName];
   if (provider1 == null)
   {
     throw new HttpException(SR.GetString("WebControl_CantFindProvider"));
   }
   return provider1;
}

角色管理授權

在實際開發中,除了使用者(User)和角色(Role)以外,我們還需要許可權(Permission)這個概念。角色更像是使用者組(Users Group),使用者可以加入一個或多個使用者組,每個使用者組又擁有多個許可權。有了許可權,我們就可以動態賦予使用者組不同的權力,比如我們可以臨時授予 A 組執行 XX 的權力,三天后我們再取消該權力,顯然沒有許可權的設計會缺乏靈活性。

ASP.NET 2.0 的角色管理授權,由 RoleManagerModule、Roles、RoleProvider、RolePrincipa 共同組成。系統會自動載入 RoleManagerModule 這個 HttpModule,Roles 為使用者提供角色相關的操作方法,而 RoleProvider 自然是提供者的抽象類別了。至於 RolePrincipa 幹什麼用,看看下面的代碼自然就明白了。

System.Web.Security.RoleManagerModule

private void OnEnter(object source, EventArgs eventArgs)
{
   // ...
   // 注意下面的代碼, RoleManagerModule 使用 RolePrincipal 替代了預設的 GenericPrincipal。
   if (!(context1.User is RolePrincipal))
   {
     context1.User = new RolePrincipal(context1.User.Identity);

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.