[转]自定义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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/549054.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

用FileZilla Server搭建ftp服务器

用FileZilla Server搭建ftp服务器 1.先在浏览器搜索 filezilla server 2.点开FileZilla软件的官网&#xff0c;下载该软件 3.下载完成后&#xff0c;按照操作流程一步步完成安装 4.打开filezilla Server软件&#xff0c;运行该软件&#xff0c;使FTP Server运行起来 5.…

不使用Vmware easy install 安装

进行了多次ubuntu的安装&#xff0c;始终发现ubuntu很多命令都没有安装到&#xff0c;用起来十分不方便&#xff0c;连最基本的init等命令都不具备&#xff0c;开始怀疑是版本的问题&#xff0c;尝试了多次&#xff0c;依旧无法解决。后来重新安装虚拟机的时候发现 选择Instal…

IP地址的分类 十进制与二进制的转换

liuweifei 1.IP地址的分类&#xff1a; ​ A类IP地址 A类IP地址就由1字节的网络地址和3字节主机地址组成&#xff0c;网络地址的最高位必须 是“0”。地址范围从1.0.0.1到127.255.255.254 &#xff08;二进制表示为&#xff1a;00000001 00000000 00000000 00000001 - 011111…

正则表达式验证密码强度

从国外网站转过来的&#xff0c;Author : Bryian Tan这个正则要求密码长度最少12位&#xff0c;包含至少1个特殊字符&#xff0c;2个数字&#xff0c;2个大写字母和一些小写字母。 (?^.{12,25}$)(?(?:.*?\d){2})(?.*[a-z])(?(?:.*?[A-Z]){2})(?(?:.*?[!#$%*()_^&…

centos配置网络笔记

centos配置笔记 &#xff08;1&#xff09; 2021.1.12 hyp 1.使用net模式连接主机网络 1.1首先配置本机网络 在本地连接的属性中开启共享选择虚拟机网络VMnet8 配置VMnet8 的IPv4属性 1.2配置虚拟机网络设置 配置网络相关ip 2.centos便捷设置网络 在安装界面中开启网络…

微软即将修复Windows 2000漏洞

微软决定在这新一年的开始让广大Windows管理员松口气&#xff1a;它计划在下周的常规补丁更新时只发布一项更新&#xff0c;这一更新将修复Windows 2000的一个严重漏洞。 漏洞的详细内容还未发布&#xff0c;但微软说对其他的平台来说&#xff0c;这一漏洞的严重级别不高。微软…

IP网址基础

IP网址基础 1.在IP网络中&#xff0c;通信节点需要有一个IP地址 ​ 以点分十进制表示&#xff0c;由32位二进制组成&#xff0c;分为网络位和主机位两部分&#xff1a;网络位&#xff0c;代表IP地址所属的网段&#xff1b;主机位&#xff0c;代表网段上的某个节点&#xff1b…

ip,子网与子网掩码

ip&#xff0c;子网与子网掩码 2021.1.13 hyp 1.概念 IP是一个网络地址&#xff0c;一个网络地址可以划分多个网段称为子网&#xff0c;通过子网掩码可以计算出划分子网的主机数 2.子网 子网掩码为255.255.255.0 的IP地址192.168.2.5的可用主机地址数为254个 3.计算子网…

Excel中Countif()函数运用技巧

Excel查找本身是星号&#xff08;*&#xff09;等通配符的方法  在Excel中&#xff0c;我们使用查找替换命令查找本身是通配符的符号&#xff0c;比如要查找波浪号(~)、星号 (*) 或问号 (?) 时&#xff0c;该如何操作呢?   查找本身是星号(*)等通配符时&#xff0c;在查找…

IP地址与二进制转换

IP地址与二进制转换 子网掩码 子网掩码是一种用来指明一个IP地址的哪些位标识的是主机所在的子网&#xff0c;以及哪些位标识的是主机的位掩码。它的作用是将IP地址分为网络地址和主机地址两部分。子网掩码可以确定子网的大小。 IP地址192.168.0.1/24&#xff0c;可知其子网掩…

DZ论坛系统 UC_KEY拿webshell

关于DZ后台拿shell&#xff0c;很多同志都很苦恼是把&#xff0c;&#xff0c;不过最近外面看到一篇文章&#xff0c;应该 才出来的把&#xff0c;&#xff0c;这里给大家发出来把&#xff0c;。。 转载者&#xff1a;littleli 我们只要得到UC_KEY&#xff0c;提交数据就可以修…

部署虚拟环境安装Linux系统(Linux就该这么学)笔记

作者&#xff1a;chenhao 1.安装配置VM虚拟机 VMware WorkStation虚拟机软件是一款桌面计算机虚拟软件&#xff0c;让用户能够在单一主机上同时运行多个不同的操作系统。每个虚拟操作系统的硬盘分区、数据配置都是独立的&#xff0c;而且多台虚拟机可以构建为一个局域网。Linux…

ISA 2006利用Bandwidth Splitter定制带宽和限制流量

ISA 2006利用Bandwidth Splitter定制带宽和限制流量本文来自: 菜鸟技术网(www.cnwan.com.cn) 详细出处参考&#xff1a;http://www.cnwan.com.cn/a/firewall/ISA/2010/0421/536.html转载于:https://blog.51cto.com/2047523/494884

子网划分基础知识

子网划分基础知识 子网划分 选定的子网掩码能创建多少个子网? 2^x个&#xff0c;其中x是子网掩码借用的主机位数。如&#xff1a;192.168.10.32/25&#xff0c;我们知道C类IP地址的默认子网掩码为&#xff1a;255.255.255.0&#xff0c;而这个IP地址的实际子网掩码是&#…

Android NDK--自己编写调用JNI

其实ubuntu中android开发环境的搭建也很简单 (1)下载android-sdk  (2)为Eclipse安装ADT&#xff0c;从help->Install New SoftWare进入&#xff0c;地址输入http://dl-ssl.google.com/android/eclipse/ 要进入NDK开发再下一个android-ndk就可以了 以上开发包均可以从http:…

IP地址 子网掩码 网络地址 广播地址 主机地址

MAC地址和IP地址 author&#xff1a;wangyifei 数据包的IP地址决定了数据包最终到达哪一个计算机&#xff0c;而MAC地址决定了该数据包下一跳由哪个设备接收&#xff0c;不一定是终点 子网掩码只有一个作用&#xff0c;就是将某个IP地址划分成网络地址和主机地址两部分。 同一…

常用VS 快捷键盘

转自:http://www.cnblogs.com/qiantuwuliang/archive/2009/05/30/1492304.html 并新加了几条。 如果你经常使用Visual Studio 2008开发程序&#xff0c;下面13个最常用快捷键你一定很熟悉。 1. F5:启动调试 2. F7 /Shift-F7:显示代码窗口或显示设计器窗口 3.Alt-Enter&#xff…

ping 工具开发日记(1)

ping 工具开发日记&#xff08;1&#xff09; 2021.1.15 hyp 0.准备 开发语言&#xff1a;python 3.8 开发环境&#xff1a;windows 7 开发工具&#xff1a;pycharm 应用功能&#xff1a;1.能实现不同系统&#xff08;windows或者linux)下ping工具 测试 ​ 2.能实现导入…

cisco ios命令

IOS命令&#xff1a; 特权模式 设置密码 配置路由器 一般 过程 CDP的 杂项 知识产权 IPX的 路由协议&#xff1a; RIP协议 IGRP的 访问列表 广域网配置 购买力平价 帧中继 键盘快捷方式 注释&#xff1a; 静态和动态路由 距离矢量和链路状态路由 内部和外部路由协议 问题与…

VMware中的虚拟机如何配置上网(Linux系统为例)

作者&#xff1a;chenhao 虚拟机上网首先要了解VMware虚拟机中的三种网络模式 一、桥接模式&#xff1a; 该模式下物理网卡和虚拟网卡的IP地址处于同一个网段&#xff0c;子网掩码、网关、DNS等参数都相同。 2.本地物理网卡和虚拟网卡通过VMnet0虚拟交换机进行桥接&#xff0…