自定义SqlMembershipProvider方法

asp 2.0自带了许多方法,很多东西都给我们封装好了,但是这样就导致了我们自定义的空间越来越小。忙碌了两个星期,一直想重写 System.Web.Security.SqlMembershipProvider,但是没有找到方法,昨天在asp.net这个晚上上找到了解决方 法,真是很兴奋。

打下可以参考一下http://forums.asp.net/p/1042049/1458049.aspx#1458049,我的大部分内容是按照里面的方法来写的。然后将中途遇到的问题做一部分解释。

步骤一:

首先下载一个ProviderToolkitSamples,下载链接如下:

http://msdn.microsoft.com/en-us/library/aa478948.aspx

因为我们要重写SqlMembershipProvider,好多要用到很多.net 2.0底层的方法,这些方法是首先的,就是我们不能直接使用,比如我们要在类的前面定义:using System.Web.SR就会报错,错误如下:'System.Web.SR' is inaccessible due to its protection level。既然我们要重写SqlMembershipProvider,那么我们就要提供这个类中所使用的所有方法。

步骤二:

安装ProviderToolkitSamples,在C:/Program Files/ASP.NET Provider Toolkit SQL Samples目录下找到下面的四个类,分别是:

SecUtil.cs,SqlConnectionHelper.cs,SQLMembershipProvider.cs,SR.cs。将他们拷贝打网站项目的app_code文件夹下面。

因为原来已经有了.vb的程序集,我们这个时候如果将.cs文件放在同一个文件夹下会编译错误,解决方法参考我前面的那一片博文App_Code目录中存放不同语言的类文件导致错误的解决方案

还有就是将SQLMembershipProvider.cs改名为MySQLMembershipProvider.cs,并且在类定义做如下修改

[c-sharp] view plain copy
  1.  public class MySQLMembershipProvider : System.Web.Security.MembershipProvider  
  2. {  
  3. /  
  4. }  

步骤三:

重新定义一个比较方便的命名空间,然后对web.config做一些修改,我的修改如下:

[c-sharp] view plain copy
  1. <add name="MySQLMembershipProvider"   
  2.       type="MyProviders.MySQLMembershipProvider"   
  3.       connectionStringName="SiteSqlServer"  
  4.       enablePasswordRetrieval="false"   
  5.       enablePasswordReset="true"   
  6.       requiresQuestionAndAnswer="false"  
  7.       minRequiredPasswordLength="3"  
  8.       minRequiredNonalphanumericCharacters="0"  
  9.       requiresUniqueEmail="false"   
  10.       passwordFormat="Hashed"   
  11.       applicationName="DotNetNuke"   
  12.       description="使用MVPHacksMembershipProvider"/>  

从上面可以看出的命名空间是MyProviders,MyProviders是来自MySQLMembershipProvider.cs文件中的

 

[c-sharp] view plain copy
  1. namespace MyProviders   
  2. {  
  3. ///  
  4. }  

接着更改membership defaultProvider,如下:

 

[c-sharp] view plain copy
  1. <membership defaultProvider="MySQLMembershipProvider" userIsOnlineTimeWindow="15">  

步骤四:

对MySQLMembershipProvider进行自定义修改。这里首先说一下, 我们从前面的

public class MySQLMembershipProvider : System.Web.Security.MembershipProvider{}

就可以看出我们自定义的MySQLMembershipProvider 继承了System.Web.Security.MembershipProvider而不是 System.Web.Security.SqlMembershipProvider。但是我们的代码确实 SqlMembershipProvider,这样就给了我们完全的自定义空间,想想就让人兴奋。

我这次项目的目标是将已有项目的加密方式改成16位的MD5加密方式,一次我在MySQLMembershipProvider类里面添加了一个求md5的方法,代码如下:

[c-sharp] view plain copy
  1. //注:自加求md5密码的静态方法  
  2. public static string GetMd5(string str)//求MD5     
  3. {  
  4.     return System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(str, "MD5").ToLower().Substring(8,16);  
  5. }  

我们知道md5加密时单向的,这和SqlMembershipProvider中的Hashed加密方式类似,所以我想到的是直接将Hashed改写为md5类型,这样其他原封不动,修改工作量大大减少。

下面来讨论加密方式,我们在源代码中可以找到

[c-sharp] view plain copy
  1. string salt = GenerateSalt();  
  2.         string pass = EncodePassword(password, (int)_PasswordFormat, salt);  

这表明加密方式是由EncodePassword(string pass, int passwordFormat, string salt)方法来控制的,下面是我修改后的代码

[c-sharp] view plain copy
  1. internal string EncodePassword(string pass, int passwordFormat, string salt)  
  2.  {  
  3.      if (passwordFormat == 0) // MembershipPasswordFormat.Clear  
  4.          return pass;  
  5.      byte[] bIn = Encoding.Unicode.GetBytes(pass);  
  6.      byte[] bSalt = Convert.FromBase64String(salt);  
  7.      byte[] bAll = new byte[bSalt.Length + bIn.Length];  
  8.      byte[] bRet = null;  
  9.      Buffer.BlockCopy(bSalt, 0, bAll, 0, bSalt.Length);  
  10.      Buffer.BlockCopy(bIn, 0, bAll, bSalt.Length, bIn.Length);  
  11.      if (passwordFormat == 1)  
  12.      { // MembershipPasswordFormat.Hashed  
  13.          HashAlgorithm s = HashAlgorithm.Create( Membership.HashAlgorithmType );  
  14.          bRet = s.ComputeHash(bAll);  
  15.          //手动添加  
  16.          return GetMd5(pass);  
  17.      } else  
  18.      {  
  19.          bRet = EncryptPassword( bAll );  
  20.      }  
  21.      return Convert.ToBase64String(bRet);  
  22.  }  

这样只要我们在配置web.config的时候使用Hashed加密方式,得到的就是MD5的密码。

步骤五

下面我们要做的就是如何修改系统中原有账户的密码。

首先我们在DNN中注册一个用户,假设我们注册账号和密码都是testmd5,那么这个时候我们去数据库中查看会发现有一个密码为

"3a25306bb46a03d6"的账户,这个就是我们新建的testmd5密码的16位md5密码。

我们通过下面的脚本来更改host的密码,让其密码也成为testmd5.

[c-sharp] view plain copy
  1. /* 
  2.  -- Database Utility --------------------------------------------------------------------------- 
  3.  Description : Reset a Password in a DotNetNuke database 
  4.  Author : Tony Tullemans 
  5.  Date Created : 18.04.2007 
  6.  Note/s : Before you run this script you must know the UserName and Password of another 
  7.  registered DNN user in the database you wish to affect. 
  8.  ----------------------------------------------------------------------------------------------- 
  9.  */  
  10.    
  11. DECLARE @databaseName VARCHAR(128)  
  12. SELECT @databaseName = DB_NAME()  
  13.    
  14. PRINT 'RESET PASSWORD IN DATABASE : ' + @databaseName  
  15. PRINT '-----------------------------' + REPLICATE('-', DATALENGTH(@databaseName ));  
  16.    
  17. DECLARE @knownUserName NVARCHAR(128)  
  18. DECLARE @lostUserName NVARCHAR(128)  
  19. DECLARE @lostUserId NVARCHAR(128)  
  20. DECLARE @knownPassword NVARCHAR(128)  
  21. DECLARE @knownSalt NVARCHAR(128)  
  22.    
  23. SET @knownUserName = 'host'  
  24. SET @lostUserName = 'testmd5'  
  25. SELECT @knownPassword = Password, @knownSalt = PasswordSalt  
  26. FROM aspnet_Membership  
  27. INNER JOIN aspnet_users  
  28. ON aspnet_Membership.UserId = aspnet_users.UserId  
  29. where UserName = @knownUserName;  
  30.    
  31. PRINT ''  
  32. PRINT 'Known Password for "' + @knownUserName + '" is : ' + @knownPassword  
  33. PRINT 'Known Password Salt for "' + @knownUserName + '" is : ' + @knownSalt  
  34.    
  35. SELECT @lostUserId = aspnet_Membership.UserId  
  36. FROM aspnet_Membership  
  37. INNER JOIN aspnet_users  
  38. ON aspnet_Membership.UserId = aspnet_users.UserId  
  39. WHERE UserName = @lostUserName;  
  40.    
  41. PRINT ''  
  42. PRINT 'UserID for "' + @lostUserName + '" is : ' + @lostUserId  
  43. PRINT ''  
  44.    
  45. IF (DATALENGTH(@lostUserName) <= 0 OR @lostUserName IS NULL)  
  46. PRINT 'Invalid Lost User Name ' + @lostUserName  
  47. ELSE BEGIN  
  48. IF (DATALENGTH(@knownUserName) <= 0 OR @knownUserName IS NULL)  
  49. PRINT 'Invalid Lost User Name ' + @lostUserName  
  50. ELSE BEGIN  
  51. IF (DATALENGTH(@knownPassword) <= 0 OR @knownPassword IS NULL)  
  52. PRINT 'Invalid Known Password ' + @knownPassword  
  53. ELSE BEGIN  
  54. IF (DATALENGTH(@knownSalt) <= 0 OR @knownSalt IS NULL)  
  55. PRINT 'Invalid Known Salt ' + @knownSalt  
  56. ELSE BEGIN  
  57. PRINT ''  
  58. PRINT 'BEFORE'  
  59. SELECT left(UserName, 12) as UserName, aspnet_Membership.UserId, left(Email, 20) as Email, Password, PasswordSalt  
  60. FROM aspnet_Membership INNER JOIN aspnet_users ON aspnet_Membership.UserId = aspnet_users.UserId  
  61. WHERE UserName IN ( @knownUserName, @lostUserName );  
  62. PRINT ''  
  63. PRINT 'Changing Password for User Id : "' + @lostUserId + '" to "' + @knownPassword + '"'  
  64. PRINT ''  
  65. UPDATE aspnet_Membership  
  66. SET Password = @knownPassword,  
  67. PasswordSalt = @knownSalt  
  68. -- SELECT UserId, Password, PasswordSalt  
  69. -- FROM aspnet_Membership  
  70. WHERE UserId = @lostUserId;  
  71. PRINT ''  
  72. PRINT 'AFTER'  
  73. SELECT left(UserName, 12) as UserName, aspnet_Membership.UserId, left(Email, 20) as Email, Password, PasswordSalt  
  74. FROM aspnet_Membership INNER JOIN aspnet_users ON aspnet_Membership.UserId = aspnet_users.UserId  
  75. WHERE UserName IN ( @knownUserName, @lostUserName );  
  76. END  
  77. END  
  78. END  
  79. END  
  80. GO  
  81. PRINT ''  
  82. PRINT ' * * * END OF SCRIPT * * *'  
  83. PRINT ''  
  84. GO  

上面的脚本在网上挺流行的,大家可能都能找到。

最后还有一步,把数据库中passwordformat改成1,因为原来hashed默认的就是1.现在用md5替换hashed,那么就应该是1.

结语

奋战两个星期,终于解决问题,其实问题并不难,很早以前就有人有同样的问题,而且早已被解决,难的如何找到解决问题的方法,如何找到资源。在这中间我发现好多都是英文资料,中文资料少之又少。这时候终于体现了英语的作用了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值