自定义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,并且在类定义做如下修改
- public class MySQLMembershipProvider : System.Web.Security.MembershipProvider
- {
- /////////////////////
- }
步骤三:
重新定义一个比较方便的命名空间,然后对web.config做一些修改,我的修改如下:
- <add name="MySQLMembershipProvider"
- type="MyProviders.MySQLMembershipProvider"
- connectionStringName="SiteSqlServer"
- enablePasswordRetrieval="false"
- enablePasswordReset="true"
- requiresQuestionAndAnswer="false"
- minRequiredPasswordLength="3"
- minRequiredNonalphanumericCharacters="0"
- requiresUniqueEmail="false"
- passwordFormat="Hashed"
- applicationName="DotNetNuke"
- description="使用MVPHacksMembershipProvider"/>
从上面可以看出的命名空间是MyProviders,MyProviders是来自MySQLMembershipProvider.cs文件中的
- namespace MyProviders
- {
- ///////////
- }
接着更改membership defaultProvider,如下:
- <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的方法,代码如下:
- //注:自加求md5密码的静态方法
- public static string GetMd5(string str)//求MD5
- {
- return System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(str, "MD5").ToLower().Substring(8,16);
- }
我们知道md5加密时单向的,这和SqlMembershipProvider中的Hashed加密方式类似,所以我想到的是直接将Hashed改写为md5类型,这样其他原封不动,修改工作量大大减少。
下面来讨论加密方式,我们在源代码中可以找到
- string salt = GenerateSalt();
- string pass = EncodePassword(password, (int)_PasswordFormat, salt);
这表明加密方式是由EncodePassword(string pass, int passwordFormat, string salt)方法来控制的,下面是我修改后的代码
- internal string EncodePassword(string pass, int passwordFormat, string salt)
- {
- if (passwordFormat == 0) // MembershipPasswordFormat.Clear
- return pass;
- byte[] bIn = Encoding.Unicode.GetBytes(pass);
- byte[] bSalt = Convert.FromBase64String(salt);
- byte[] bAll = new byte[bSalt.Length + bIn.Length];
- byte[] bRet = null;
- Buffer.BlockCopy(bSalt, 0, bAll, 0, bSalt.Length);
- Buffer.BlockCopy(bIn, 0, bAll, bSalt.Length, bIn.Length);
- if (passwordFormat == 1)
- { // MembershipPasswordFormat.Hashed
- HashAlgorithm s = HashAlgorithm.Create( Membership.HashAlgorithmType );
- bRet = s.ComputeHash(bAll);
- //手动添加
- return GetMd5(pass);
- } else
- {
- bRet = EncryptPassword( bAll );
- }
- return Convert.ToBase64String(bRet);
- }
这样只要我们在配置web.config的时候使用Hashed加密方式,得到的就是MD5的密码。
步骤五
下面我们要做的就是如何修改系统中原有账户的密码。
首先我们在DNN中注册一个用户,假设我们注册账号和密码都是testmd5,那么这个时候我们去数据库中查看会发现有一个密码为
"3a25306bb46a03d6"的账户,这个就是我们新建的testmd5密码的16位md5密码。
我们通过下面的脚本来更改host的密码,让其密码也成为testmd5.
- /*
- -- Database Utility ---------------------------------------------------------------------------
- Description : Reset a Password in a DotNetNuke database
- Author : Tony Tullemans
- Date Created : 18.04.2007
- Note/s : Before you run this script you must know the UserName and Password of another
- registered DNN user in the database you wish to affect.
- -----------------------------------------------------------------------------------------------
- */
- DECLARE @databaseName VARCHAR(128)
- SELECT @databaseName = DB_NAME()
- PRINT 'RESET PASSWORD IN DATABASE : ' + @databaseName
- PRINT '-----------------------------' + REPLICATE('-', DATALENGTH(@databaseName ));
- DECLARE @knownUserName NVARCHAR(128)
- DECLARE @lostUserName NVARCHAR(128)
- DECLARE @lostUserId NVARCHAR(128)
- DECLARE @knownPassword NVARCHAR(128)
- DECLARE @knownSalt NVARCHAR(128)
- SET @knownUserName = 'host'
- SET @lostUserName = 'testmd5'
- SELECT @knownPassword = Password, @knownSalt = PasswordSalt
- FROM aspnet_Membership
- INNER JOIN aspnet_users
- ON aspnet_Membership.UserId = aspnet_users.UserId
- where UserName = @knownUserName;
- PRINT ''
- PRINT 'Known Password for "' + @knownUserName + '" is : ' + @knownPassword
- PRINT 'Known Password Salt for "' + @knownUserName + '" is : ' + @knownSalt
- SELECT @lostUserId = aspnet_Membership.UserId
- FROM aspnet_Membership
- INNER JOIN aspnet_users
- ON aspnet_Membership.UserId = aspnet_users.UserId
- WHERE UserName = @lostUserName;
- PRINT ''
- PRINT 'UserID for "' + @lostUserName + '" is : ' + @lostUserId
- PRINT ''
- IF (DATALENGTH(@lostUserName) <= 0 OR @lostUserName IS NULL)
- PRINT 'Invalid Lost User Name ' + @lostUserName
- ELSE BEGIN
- IF (DATALENGTH(@knownUserName) <= 0 OR @knownUserName IS NULL)
- PRINT 'Invalid Lost User Name ' + @lostUserName
- ELSE BEGIN
- IF (DATALENGTH(@knownPassword) <= 0 OR @knownPassword IS NULL)
- PRINT 'Invalid Known Password ' + @knownPassword
- ELSE BEGIN
- IF (DATALENGTH(@knownSalt) <= 0 OR @knownSalt IS NULL)
- PRINT 'Invalid Known Salt ' + @knownSalt
- ELSE BEGIN
- PRINT ''
- PRINT 'BEFORE'
- SELECT left(UserName, 12) as UserName, aspnet_Membership.UserId, left(Email, 20) as Email, Password, PasswordSalt
- FROM aspnet_Membership INNER JOIN aspnet_users ON aspnet_Membership.UserId = aspnet_users.UserId
- WHERE UserName IN ( @knownUserName, @lostUserName );
- PRINT ''
- PRINT 'Changing Password for User Id : "' + @lostUserId + '" to "' + @knownPassword + '"'
- PRINT ''
- UPDATE aspnet_Membership
- SET Password = @knownPassword,
- PasswordSalt = @knownSalt
- -- SELECT UserId, Password, PasswordSalt
- -- FROM aspnet_Membership
- WHERE UserId = @lostUserId;
- PRINT ''
- PRINT 'AFTER'
- SELECT left(UserName, 12) as UserName, aspnet_Membership.UserId, left(Email, 20) as Email, Password, PasswordSalt
- FROM aspnet_Membership INNER JOIN aspnet_users ON aspnet_Membership.UserId = aspnet_users.UserId
- WHERE UserName IN ( @knownUserName, @lostUserName );
- END
- END
- END
- END
- GO
- PRINT ''
- PRINT ' * * * END OF SCRIPT * * *'
- PRINT ''
- GO
上面的脚本在网上挺流行的,大家可能都能找到。
最后还有一步,把数据库中passwordformat改成1,因为原来hashed默认的就是1.现在用md5替换hashed,那么就应该是1.
结语
奋战两个星期,终于解决问题,其实问题并不难,很早以前就有人有同样的问题,而且早已被解决,难的如何找到解决问题的方法,如何找到资源。在这中间我发现好多都是英文资料,中文资料少之又少。这时候终于体现了英语的作用了。
致谢
john,M2Land,从不闲聊,牛哥
http://blog.csdn.net/xw13106209/article/details/5133690
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?