Summary: The Membership component of asp.net 2.0 provides a set of very simple and easy-to-use interfaces for developers to perform user management and user verification. This article will briefly analyze its implementation principle, introduce how to use it correctly, and how to extend it.
1. MembershipProvider abstract class
In many cases, we do not use this class directly when using Membership. The MembershipProvider class defines some abstract methods and abstract attributes. It is these methods and attributes that constitute the basic specifications of the Membership interface, and the functions of using Membership within the .NET framework are all called through this type. Inherited classes provide user management functions in different environments by implementing these interfaces, and have no impact on the Membership framework itself. Let’s take a look at the prototype definition of 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, string newPasswordQuestion, string newPasswordAnswer);
public abstract MembershipUser CreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, object providerUserKey, out MembershipCreateStatus status);
protected virtual byte[] DecryptPassword(byte[] encodedPassword);
public abstract bool DeleteUser(string username, bool deleteAllRelatedData);
internal string EncodePassword (string pass, int passwordFormat, string salt);
protected virtual byte[] EncryptPassword(byte[] password);
public abstract MembershipUserCollection FindUsersByEmail(string emailToMatch, int pageIndex, int pageSize, out int totalRecords);
public abstract MembershipUserCollection FindUsersByName(string usernameToMatch , int pageIndex, int pageSize, out int totalRecords);
internal string GenerateSalt();
public abstract MembershipUserCollection GetAllUsers(int pageIndex, int pageSize, out int totalRecords);
public abstract int GetNumberOfUsersOnline();
public abstract string GetPassword(string username, string answer);
public abstract MembershipUser GetUser(object providerUserKey, bool userIsOnline);
public abstract MembershipUser GetUser(string username, bool userIsOnline);
internal MembershipUser GetUser(string username, bool userIsOnline, bool throwOnError);
public abstract string GetUserNameByEmail(string email);
protected virtual void OnValidatingPassword(ValidatePasswordEventArgs e);
public abstract string ResetPassword(string username, string answer);
internal string UnEncodePassword(string pass, int passwordFormat);
public abstract bool UnlockUser(string userName);
public abstract void UpdateUser(MembershipUser user);
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 MaxInvalidPasswordAttempts ...{ get; }
public abstract int MinRequiredNonAlphanumericCharacters ...{ get; }
public abstract int MinRequiredPasswordLength ...{ get; }
public abstract int PasswordAttemptWindow ...{ get; }
public abstract MembershipPasswordFormat PasswordFormat ...{ get; }
public abstract string PasswordStrengthRegularExpression ... { get; }
public abstract bool RequiresQuestionAndAnswer ...{ get; }
public abstract bool RequiresUniqueEmail ...{ get; }
// Fields
private MembershipValidatePasswordEventHandler _EventHandler;
private const int SALT_SIZE_IN_BYTES = 0x10;
}
The modifier internal is several methods that are auxiliary methods for passwords, used to encrypt, decrypt and verify passwords. But there seem to be some problems with the design here. It seems a bit inappropriate to define these methods as internal scope. These methods are defined in the base class so that they can be reused, but from the effect point of view, this is not the case, because internal Members are only allowed to be used within this assembly (under normal circumstances, other methods such as reflection are not included), which means that our own extended MembershipProvider cannot use these methods. And judging from the current scope of application, these methods are currently only used in SqlMembershipProvider, so I think these method modifiers should be changed to protected.
2. Membership static class
As mentioned above, under normal circumstances we will not directly use the MembershipProvider abstraction, because it involves the problem of how to instantiate the real Membership service class, and generally involves the configuration and instantiation of objects. These are all relatively difficult questions, and for beginners, they are not easy to master. In the .NET framework, this layer of complex relationships is shielded through the static class Membership (Static Class). In addition to shielding users from reading configuration files, initial objects and other basic tasks, Membership (Static Class) also plays an important role in reloading all MembershipProviders, so there are APIs. In order to make it more convenient for users to use, Membership (Static Class) also reloads these methods. Loaded as a static method, and provides richer overloaded implementations based on the basic API of MembershipProvider for users to call. This directly supports whether it is in the UI layer or other projects, just refer to the System.Web.Security namespace, and you can enjoy the various conveniences provided by Membership without worrying about any details. Let's take a look at the prototype definition of Membership (Static Class): (Use Lutz Roder's .NET Reflector to view all its implementations.)
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 MembershipUser CreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, out MembershipCreateStatus status);
public static MembershipUser CreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, object providerUserKey, out MembershipCreateStatus status);
public static bool DeleteUser(string
public static bool DeleteUser(stringusername
, bool deleteAllRelatedData);
public static MembershipUserCollectionFindUsersByEmail(string emailToMatch);
public static MembershipUserCollection FindUsersByEmail(string emailToMatch, int pageIndex, int pageSize, out int totalRecords);
public static MembershipUserCollection FindUsersByName(string usernameToMatch ;
, out int totalRecords);
private static string GetCurrentUserName();
public static int GetNumberOfUsersOnline();
public static MembershipUser GetUser();
public static MembershipUser GetUser(bool userIsOnline);
public static MembershipUser GetUser(object providerUserKey);
public static MembershipUser GetUser( string username);
public static MembershipUser GetUser(object providerUserKey, bool userIsOnline);
public static MembershipUser GetUser(string username, bool userIsOnline);
public static string GetUserNameByEmail(string emailToMatch);
private static void Initialize();
public static void UpdateUser(MembershipUser 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; }
internal static bool IsHashAlgorithmFromMembershipConfig ...{ get; }
public static int MaxInvalidPasswordAttempts ...{ get; }
public static int MinRequiredNonAlphanumericCharacters ...{ get; }
public static int MinRequiredPasswordLength ...{ get; }
public static int PasswordAttemptWindow ... { get; }
public static string PasswordStrengthRegularExpression ...{ get; }
public static MembershipProvider Provider ...{ get; }
public static MembershipProviderCollection Providers ...{ get; }
public static bool RequiresQuestionAndAnswer ...{ get; }
public static int UserIsOnlineTimeWindow ...{ get; }
// Fields
private static char[] punctuations;
private static bool s_HashAlgorithmFromConfig;
privatestatic string s_HashAlgorithmType;
privatestatic bool s_Initialized;
private static Exception s_InitializeException;
private static object s_lock;
private static MembershipProvider s_Provider;
private static MembershipProviderCollection s_Providers;
private static int s_UserIsOnlineTimeWindow;
}
Having said that, I have to say a few words. In the process of looking at the Membership (Static Class) implementation code, you can find that every Membersip API overload ends up calling the method of the attribute Provider. The type of this attribute is the MembershipProvider type. Only when you see this, you may understand Let’s understand the important role of MembershipProvider. There is also a Providers attribute, which is to obtain all the Membership service classes configured in web.config. They are all static properties, but how are they instantiated? By calling the Membership.Initialize() method, every time these two properties are called, this method will be called to determine whether the service class provided by Membership has been initialized. If not, the configuration service class will be called to read the configuration. content to initialize. At this point it may not be difficult for you to understand why it is so easy for us to use!
3. Introduction and usage configuration of SqlMembershipProvider
OK. Through the above introduction, you should be able to basically understand the overall structure of Membership, right? (If you haven't yet, it may be that you haven't opened Lutz Roder's .NET Reflector to analyze its implementation code, or you haven't understood the role of abstract classes yet). No matter what, our ultimate goal is to learn how to use it.
Before that, I first want to introduce the two MembershipProvider implementation classes provided in the .NET framework: ActiveDirectoryMembershipProvider and SqlMembershipProvider (How do you know these two classes? You can see all inherited classes in Derived Types of MembershipProvider. ) The former provides basic user management under Active Directory (I have not practiced it), and the latter is the user management implementation based on SqlServer that we most often use.
It’s time to introduce how to use it. In fact, there are already articles on this in the garden ((Translation) How to use Membership in ASP.NET 2.0), so I won’t waste any more words. But here I want to tell you the most direct way to learn and use it for reference. Find and open machine.config on the system disk, find the AspNetSqlMembershipProvider node, and see if you can see it. In fact, this is the most basic Membership configuration, but it lacks the specification of the defaultProvider attribute. After specifying this attribute, you can use Login control, there is no need to use any code for user login verification. If you don’t believe it, you can try it. (As for Forms verification, I won’t introduce it here. You can refer to relevant information. For more information about SqlMembershipProvider, please refer to MSDN).
4. How to customize MembershipProvider, other existing MembershipProvider resources
So, how do we customize a MembershipProvider? In fact, if you already understand the structure of Membership, I believe it is not difficult for you. However, considering that it is still a certain amount of work and difficulty to write a complete MembershipProvider. For us, more places may be to extend existing Provider, such as SqlMembershipProvider. In fact, this is very simple. We only need to inherit from SqlMembershipProvider (quietly tell you, what is saved in the config parameter of the Initialize method is the attribute name and value of the corresponding configuration section of the Provider) and then extend and rewrite the required methods. . When using it, in the Provider configuration section, change the value of type to your class name and it will be OK.
Finally, there are already many MembershipProviders in different environments on the market, such as mysql, Oracle, etc. Here is the implementation of Mysql: http://www.codeproject.com/aspnet/mysqlmembershipprovider.asp . There are more different implementations. I believe you can find more help from Google.
Okay, I’ve said too much. I hope it can be helpful to you who have taken the trouble to read this blog. Thank you^_*