首页 > 编程 > .NET > 正文

ASP.NET 2.0 Membership

2024-07-10 13:09:45
字体:
来源:转载
供稿:网友

摘要: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, 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;

}

 


其中修饰符为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 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 username);

      public static bool deleteuser(string username, bool deleteallrelateddata);

      public static membershipusercollection findusersbyemail(string emailtomatch);

      public static membershipusercollection findusersbyemail(string emailtomatch, int pageindex, int pagesize, out int totalrecords);

      public static membershipusercollection findusersbyname(string usernametomatch);

      public static membershipusercollection findusersbyname(string usernametomatch, int pageindex, int pagesize, out int totalrecords);

      public static string generatepassword(int length, int numberofnonalphanumericcharacters);

      public static membershipusercollection getallusers();

      public static membershipusercollection getallusers(int pageindex, int pagesize, 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;

      private static string s_hashalgorithmtype;

      private static 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;

}

 

说到这里,就不得不多罗嗦两句。在看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的您有所帮助,谢谢 ^_*

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表