• [转]自定义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,并且在类定义做如下修改

    view plaincopy to clipboardprint?
     public class MySQLMembershipProvider : System.Web.Security.MembershipProvider  
    {  
    /////////////////////  

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

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

    view plaincopy to clipboardprint?
    <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"/> 
      <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文件中的

    view plaincopy to clipboardprint?
    namespace MyProviders   
    {  
    ///////////  

    namespace MyProviders
    {
    ///////////
    }

    接着更改membership defaultProvider,如下:

    view plaincopy to clipboardprint?
    <membership defaultProvider="MySQLMembershipProvider" userIsOnlineTimeWindow="15"> 
     <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的方法,代码如下:

    view plaincopy to clipboardprint?
    //注:自加求md5密码的静态方法  
    public static string GetMd5(string str)//求MD5     
    {  
        return System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(str, "MD5").ToLower().Substring(8,16);  

            //注:自加求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类型,这样其他原封不动,修改工作量大大减少。

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

    view plaincopy to clipboardprint?
    string salt = GenerateSalt();  
            string pass = EncodePassword(password, (int)_PasswordFormat, salt); 
        string salt = GenerateSalt();
                string pass = EncodePassword(password, (int)_PasswordFormat, salt);

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

    view plaincopy to clipboardprint?
    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);  
     } 
           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.view plaincopy to clipboardprint?
    /* 
     -- 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 
    /*
     -- 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,从不闲聊,牛哥

    本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/xw13106209/archive/2010/01/05/5133690.aspx

  • 相关阅读:
    Linux 常用命令
    公钥,私钥和数字签名
    MySQL中的datetime与timestamp比较
    SQL开发技巧
    socket心跳包机制
    vue 路由回退,实现刷新原页面数据
    HTTP1.0、HTTP1.1 和 HTTP2.0 的区别
    Xshell常用命令
    学习Dart flutter --1
    学习JavaScript数据结构与算法(第2版)--01
  • 原文地址:https://www.cnblogs.com/scgw/p/1931816.html
Copyright © 2020-2023  润新知