摘要:asp.net 2.0的Membership元件提供了一組非常簡單易用的介面供開發者進行使用者管理,使用者驗證。本文將它對它的實作原理進行簡單的分析,介紹如何正確的使用,以及如何對它進擴展。
一、MembershipProvider抽象類別
在很多情況下,在使用Membership的時候我們並不會直接使用到這個類別。在MembershipProvider類別定義的都是一些抽象方法和抽象屬性,就是這些方法和屬性構成了Membership介面的基本規範,而且在.NET 框架內部使用Membership的功能都是透過這個類型呼叫的。繼承類別透過實作這些介面來提供不用環境下的使用者管理功能,並且對Membership框架本身並沒有影響,以下來看看MembershipProvider原形定義:
public abstract class MembershipProvider : ProviderBase
...{
// Events
public event MembershipValidatePasswordEventHandler ValidatingPassword;
// Methods
protected MembershipProvider();
public abstract bool ChangePassword(string username, string oldPassword, string newPassword);
public abstract bool ChangePasswordQuestionAndAnswer(string username, string password Userstring Userpassword, Usercnable Userstring ing
username, string
password, string email, string passwordQuestion,string
passwordAnswer, bool isApproved, object providerUserKey, out MembershipCreateStatus status);
string
EncodePassword (string pass, int passwordFormat, string salt);
protected virtual byte[] EncryptPassword(byte[] 密碼
yName
(string usernameToMatch , int pageIndex, int pageSize, out int totalRecords);
internal string GenerateSalt();
public
abstract MembershipUserCollection GetAllUsers(int pageIndex, int pageSize, out int totalcords);
string
answer
)
;
protected virtual void OnValidatingPassword(ValidatePasswordEventArgs e);
public abstract string ResetPassword(string username, string answer);
internal string UnEncodePassword(stringpass
, int passwordFormat)
;
public abstract bool ValidateUser(string username, string password);
// Properties
public abstract string ApplicationName ...{ get; set; }
public
abstract bool EnablePasswordReset ...{ get; }
public abstract bool EnablePasswordRetrieval ...{ get; }
public abstract int MaxInvalidwordAttempts ...{ get;
abstract int MinRequiredNonAlphanumericCharacters ...{ get; }
public abstract int MinRequiredPasswordLength ...{ get; }
publicabstract int PasswordAttemptWindow ...
{ get; } public abstract MembershipPasswordFormatatwordFormationatpidkityat getattract untract get 完成
單詞... { get; }
public abstract bool RequiresQuestionAndAnswer ...{ get; }
public abstract bool RequiresUniqueEmail ...{ get; }
// Fields
private MembershipValidatePasswordEventHandler _EventHandler;
private const int SALT_SIZE_IN_BYTES = 0x10;
}
其中修飾符為internal是幾個方法是密碼的輔助方法,用於加密,解密和驗證密碼。但這邊的設計似乎有一些問題,將這些方法定義為internal範圍好像有點不妥,將這些方法定義在基類中,就是為了能夠被複用,但是從效果上來看,不是這樣的,因為internal的成員只允許在本程序集內被使用(正常情況下,不包括反射等其它方法),這就是說我們自己擴展的MembershipProvider是無法使用到這些方法的。而且從目前應用範圍來看,目前這些方法也只有在SqlMembershipProvider中被使用到,所以我認為應該將這些方法修飾符修改為protected。
二、Membership 靜態類別
上面提到過,一般情況下我們都不會直接去使用到MembershipProvider抽象,因為這涉及到如何去實例化真正的Membership服務類別的問題,涉及到配置和實例化物件的問題一般都是比較棘手的問題,對初學者來說,想要掌握也不是那麼容易。那在.NET框架中就是透過Membership(Static Class)這個靜態類別來屏蔽掉這一層的複雜關係。 Membership(Static Class)除了用戶屏蔽讀配置文件,初始物件等一些基本工作外,還有一個重要的作用就是重載所有的MembershipProvider所以有API,甚至為了讓用戶更加方便的使用,將這些方法重載為靜態方法,並且提供了MembershipProvider基本API基礎上更豐富的重載實作供使用者呼叫。這就直接支援了不管是在UI層,還是其它的各個工程,只需要引用System.Web.Security命名空間,就可以不用關心任何細節的享受到Membership給我們提供的各種便利。下面來看看Membership(Static Class)的原型定義:(利用Lutz Roder's .NET Reflector可以查看它的所有實作。)
public static class Membership
...{
// Events
public static event MembershipValidatePasswordEventHandler ValidatingPassword;
// Methods
static Membership();
public static MembershipUser CreateUser(string username, string password);
public static MembershipUser CreateUser(string username, string password, string email);
public static MstringUser CreateUser(string Userword, string email); public static Mstring User CreateUser(stringsname, str. passwordQuestion, string passwordAnswer, bool isApproved, out MembershipCreateStatus status);
public static MembershipUser CreateUser(string username, string password, string email, string passwordQuestion, string 信息
static bool DeleteUser(string username);
public static bool DeleteUser(string username, bool deleteAllRelatedData);
public static MembershipUserCollection FindUsersByEmail(string emailToMatch)
; public static Member UserCollection FindUsersByter e(
mailToMatch); public static Member UserCollection FindUsersByter e(string edemail,almaildea), com ic MembershipUserCollection FindUsersByName(string usernameToMatch )
;
ollection
GetAllUsers(int pageIndex, int
pageSize
, out int totalRecords);
private static string GetCurrentUserName();
public static int GetNumberOfUsersOnline()
; public static MembershipUser GetUser()
;public
static MUser HUser GetUser(bool UserIsOnline)
;
string username);
public static MembershipUser GetUser(object providerUserKey, bool userIsOnline);
public static MembershipUser GetUser(string username, bool userIsOnline);
publicstatic
string GetUserNameByEmail(string eprivates Userstion
User片); user);
public static bool ValidateUser(string username, string password);
// Properties
public static string ApplicationName ...{ get; set; }
public static bool EnablePasswordReset ...{ get; }
public static bool EnablePasswordRetrieval ...{ get; }
public static string HashAlgorithmType ...{ get; } internalget; }
internalget
;static bool IsHashAlgorithmFromMembershipConfig ...{ get; }
public static int MaxInvalidPasswordAttempts ...{ get; }
publicstatic int MinRequiredNonAlphanumericCharacters ...{ gets; }
public tempicint MinRequiredNonAlphanumericCharacters ...{ getdow }
public tempic int MinRequired intools intom { get; }
public static string PasswordStrengthRegularExpression ...{ get; }
public static MembershipProvider Provider ...{ get; }
public static MembershipProviderCollection Providers ...{ get; }
public static boolquiresQuestshipProviderCollection
Providers ...{ get; }public static
boolquiresQuestionAndgetswer.int UserIsOnlineTimeWindow ...{ get; }
// Fields
private static char[] punctuations;
private static bool s_HashAlgorithmFromConfig;
privatestatic string s_HashAlgorithmType;
private
static bool s_Initialized;
private sception private;
static MembershipProvider s_Provider;
private static MembershipProviderCollection s_Providers;
private static int s_UserIsOnlineTimeWindow;
}
說到這裡,就得多囉嗦兩句。在看Membership(Static Class)實作程式碼的過程中,可以發現,每一個Membersip API重載都最後都是呼叫屬性Provider的方法,這個屬性的類型就是MembershipProvider類型,只有看到這裡,你或許才會理解MembershipProvider的重要作用了吧。還有一個Providers屬性,這個屬性就是要取得web.config中配置的所有的Membership提供服務類別。它們都是靜態屬性,但是它們怎麼去實例化的呢?就是透過呼叫Membership. Initialize()這個方法,在每次呼叫這兩個屬性的時候,都會呼叫這個方法去判斷是否已初始化了Membership提供服務類了,如果沒有則去呼叫配置服務類,讀取配置內容,從而進行初始化。到此你可能也就不難理解了,為什麼我們用那麼簡單了!
三、SqlMembershipProvider介紹和使用配置
OK,透過上面的介紹應該基本上可以了解Membership的整體結構了吧? (如何還沒有,可能是你沒有打開Lutz Roder's .NET Reflector去分析它的實作程式碼,或是對抽象類別的作用還沒搞清楚)。不管怎麼樣,我們最終的目的就是要學會如何使用。
在這之前,我先要介紹一下,在.NET 框架中提供的兩個MembershipProvider實作類別:ActiveDirectoryMembershipProvider和SqlMembershipProvider(如何知道這兩個類別的?在MembershipProvider的Derived Types就可以看到所有的繼承類別了。 )前者是提供基本活動目錄下的使用者管理(我也沒有實踐過),後者就是我們最常使用到的基於SqlServer的使用者管理實作。
到了介紹如何使用了,其實園子裡已經有了這方面的文章((翻譯)怎麼在ASP.NET 2.0中使用Membership),我也不多費口舌了。但這邊要告訴大家一個最直接的學習和參考使用的方法。在系統碟找到並開啟machine.config,找到AspNetSqlMembershipProvider節點,看到沒有,其實這個就是一個最基本的Membership配置了,只不過是還少了一個defaultProvider屬性的指定,指定了這個屬性後,你再使用Login控件,進行使用者登入驗證就無需使用任何程式碼了。不信你可以試試。 (關於Forms驗證,就不在這裡多做介紹,可以參考相關資料。關於SqlMembershipProvider的更多屬性的介紹可以參考MSDN)。
四、如何自訂MembershipProvider,現有其它的MembershipProvider資源
那麼,我們要如何去自訂一個MembershipProvider呢?其實如果你已經了解了Membership的結構後我相信對你來說已經不是一件很難的事了,但是考慮到要完整的寫一個MembershipProvider還是有一定的工作量和難度的。對我們來說,更多的地方可能是對現有的Provider進行擴展,例如SqlMembershipProvider。那其實這是非常簡單的,我們只需要繼承自SqlMembershipProvider,(悄悄告訴你,在Initialize方法config參數中保存的就是Provider對應配置節的屬性名稱和值)然後擴展和重寫所需的方法就可以了。使用的時候,在Provider配置節中,將type的值改為你的類別名稱就OK了。
最後,市面上已經有好多不同環境的MembershipProvider了,如mysql,Oracle等。這裡給出Mysql 的實作:http: //www.codeproject.com/aspnet/mysqlmembershipprovider.asp ,更多不同的實現,相信你從google找到更多的幫助。
好了,說太多了,說了這麼多希望能對不辭辛苦看完這篇blog的您有所幫助,謝謝^_*