# Wednesday, June 13, 2007

asp.net 2.0中引入的Membership机制给我们做web开发带来很多便利,使得我们在做很多项目开发时处理用户和角色及权限问题时减少了相当的工作量。不过我们开发中可能会碰到一个小小的问题如下:

我们知道MembershipUser中有如下重载的方法

  • MembershipUser.ResetPassword () :将用户密码重置为一个自动生成的新密码。
  • MembershipUser.ResetPassword (String passwordAnswer) :将用户密码重置为一个自动生成的新密码。

msdn中有如下描述:

ResetPassword 调用 ProviderName 属性所引用的成员资格提供程序的 MembershipProvider.ResetPassword 方法,以将成员资格用户的密码重置为自动生成的新密码。然后将该新密码返回到调用方。

如果 EnablePasswordReset 为 false,则成员资格提供程序将返回一个异常。

如果 RequiresQuestionAndAnswer 为 true,则必须使用以密码提示问题答案作为参数的 ResetPassword 重载方法,并提供成员资格用户的密码。如果需要密码答案并提供了不正确的密码答案,成员资格提供程序将引发 MembershipPasswordException。

而另外一个方法MembershipUser.ChangePassword(String oldPassword, String newPassword) 又必须提供原始密码,那么这里就产生了一个矛盾:我们希望用户能够通过安全问题和答案来作为找回密码,又希望管理员可以重置某用户的密码怎么办?上述方法均无法直接使用,要么使用MembershipUser.ResetPassword ()而无安全问题和答案验证,要么必须知道问题答案或者原始密码,我们知道这些安全相关的东西我们都是加密的,而且往往采用单向编码的方式,也是说我们不可能轻易的通过读取数据库数据知道用户的答案和旧密码!那么好,如何解决这个问题呢?下面我来提供一个小的解决方案:

Membership的数据库中包含有一个设置用户密码的存储过程:

CREATE PROCEDURE aspnet_Membership_SetPassword
(

 @ApplicationName nvarchar(256),

 @UserName nvarchar(256),

 @NewPassword nvarchar(128),

 @PasswordSalt nvarchar(128),

 @CurrentTimeUtc datetime,

 @PasswordFormat int = 0
)

返回值:成功返回 0;
用户不存在,返回 1;

那么ok,我们开始解决我们的需求吧!思路很简单我们先设置用户一个默认的密码,然后以该密码为旧密码使用MembershipUser.ChangePassword(String oldPassword, String newPassword) 修改用户的密码。下面的代码是在以DataAccess.RunProcedure方法是已经实现的执行存储过程的方法为前提编写的:

public class MembershipSafe
 {
     public static string ResetPassword(string username)
     {
         //将用户密码修改为8位且包含一个特殊符号的随机密码
         return ResetPassword(username, Membership.GeneratePassword(8,1));
    }
  
     public static string ResetPassword(string username, string newpassword)
     {
         //先将用户密码修改为123123
  
         SqlParameter[] _sp = {
                              new SqlParameter("@ApplicationName",Membership.ApplicationName)
                             ,new SqlParameter("@UserName",username)
                             ,new SqlParameter("@NewPassword","1M4h3eZLAKW1WbVTTwYJiJZa33w=")
                             ,new SqlParameter("@PasswordSalt","rcVy3pCccZ9tXW7NHp1Maw==")
                             ,new SqlParameter("@CurrentTimeUtc",DateTime.Now)
                             ,new SqlParameter("@PasswordFormat",1)
         };
         bool op = DataAccess.RunProcedure("aspnet_Membership_SetPassword", _sp) == 0;
         //以123123为原始密码,修改为新密码
         Membership.GetUser(username).ChangePassword("123123", newpassword);
         return newpassword;
     }
 }

注:以上代码仅做参考,不一定是符合您具体项目的需求,比如有人可能会继续问修改了密码怎么告诉用户啊,答案是发邮件或者电话通知啊,哈哈~~

推荐浏览:

posted on Wednesday, June 13, 2007 2:41:02 PM (China Standard Time, UTC+08:00)  #    Comments [0]
# Saturday, May 05, 2007

    最近不少Web技术圈内的朋友在讨论协议方面的事情,有的说web开发者应该熟悉web相关的协议,有的则说不用很了解。个人认为这要分层次来看待这个问题,对于一个新手或者刚入门的web开发人员而言,研究协议方面的东西可能会使得web开发失去趣味性、抹煞学习积极性,这类人应该更多的了解基本的Web技术使用。而对于在该行业工作多年的老鸟来说,协议相关的内容、标准相关内容应该尽量多些的了解,因为只有这样才能使得经手的web系统更加优秀(安全、漂亮、快速、兼容性好、体验好……)。本文我们来说一下MIME 协议的一个扩展Content-disposition。

    我们在开发web系统时有时会有以下需求:

  • 希望某类或者某已知MIME 类型的文件(比如:*.gif;*.txt;*.htm)能够在访问时弹出“文件下载”对话框
  • 希望以原始文件名(上传时的文件名,例如:山东省政府1024号文件.doc)提供下载,但服务器上保存的地址却是其他文件名(如:12519810948091234_asdf.doc)
  • 希望某文件直接在浏览器上显示而不是弹出文件下载对话框
  • ……………………

    要解决上述需求就可以使用Content-disposition来解决。第一个需求的解决办法是

Response.AddHeader "content-disposition","attachment; filename=fname.ext"
 
将上述需求进行归我给出如下例子代码:
public static void ToDownload(string serverfilpath,string filename)
{
    FileStream fileStream = new FileStream(serverfilpath, FileMode.Open);
    long fileSize = fileStream.Length;
    HttpContext.Current.Response.ContentType = "application/octet-stream";
    HttpContext.Current.Response.AddHeader("Content-Disposition", "attachment; filename=\"" + UTF_FileName(filename) + "\";");
    ////attachment --- 作为附件下载
    ////inline --- 在线打开
    HttpContext.Current.Response.AddHeader("Content-Length", fileSize.ToString());
    byte[] fileBuffer = new byte[fileSize];
    fileStream.Read(fileBuffer, 0, (int)fileSize);
    HttpContext.Current.Response.BinaryWrite(fileBuffer);
    fileStream.Close();
    HttpContext.Current.Response.End();
}

public static void ToOpen(string serverfilpath, string filename)
{
    FileStream fileStream = new FileStream(serverfilpath, FileMode.Open);
    long fileSize = fileStream.Length;
    HttpContext.Current.Response.ContentType = "application/octet-stream";
    HttpContext.Current.Response.AddHeader("Content-Disposition", "inline; filename=\"" + UTF_FileName(filename) + "\";");
    HttpContext.Current.Response.AddHeader("Content-Length", fileSize.ToString());
    byte[] fileBuffer = new byte[fileSize];
    fileStream.Read(fileBuffer, 0, (int)fileSize);
    HttpContext.Current.Response.BinaryWrite(fileBuffer);
    fileStream.Close();
    HttpContext.Current.Response.End();
}

private static string UTF_FileName(string filename)
{
    return HttpUtility.UrlEncode(filename, System.Text.Encoding.UTF8);
}

 

简单的对上述代码做一下解析,ToDownload方法为将一个服务器上的文件(serverfilpath为服务器上的物理地址),以某文件名(filename)在浏览器上弹出“文件下载”对话框,而ToOpen是将服务器上的某文件以某文件名在浏览器中显示/打开的。注意其中我使用了UTF_FileName方法,该方法很简单,主要为了解决包含非英文/数字名称的问题,比如说文件名为“衣明志.doc”,使用该方法客户端就不会出现乱码了。

 需要注意以下几个问题:

  1. Content-disposition是MIME协议的扩展,由于多方面的安全性考虑没有被标准化,所以可能某些浏览器不支持,比如说IE4.01
  2. 我们可以使用程序来使用它,也可以在web服务器(比如IIS)上使用它,只需要在http header上做相应的设置即可

可参看以下几篇文档:

posted on Saturday, May 05, 2007 3:03:14 AM (China Standard Time, UTC+08:00)  #    Comments [0]
# Friday, April 06, 2007

数据库镜像是SQL Server 2005的一个新特性,它允许你将一个SQL Server中的数据库内容镜像到另一个SQL Server上。它还让你可以在发生错误的时候,通过镜像数据库来进行错误恢复。镜像的拷贝是一个备用的拷贝,不能直接访问,它只用在错误恢复的情况下。SQL2005的这一特性给数据库系统维护人员带来了不错的实惠,而给最终用户的体验也是不错的。至于如何配置数据库镜像系统,大家可以到TechNet 中文网络广播 中查找一下相关视频教程,尤其推荐大家去看看MVP牛可的相关讲座视频哦。再这里就不多说了。我们直奔主题吧!!

在使用数据库镜像功能时,如果我们使用的是工作组,那么我们需要注意一下数据库用户的问题:用普通方式创建的数据库用户,在主数据库中和镜像数据库中是有一些差异的,而这个差异最终会造成一个“奇怪”的结果,我们在主数据库和镜像数据库中对某数据库影射的“相同用户”,在发生故障转移后数据库验证会发生异常,称该用户无法登录我们的数据库,WHY? 原来是两个数据库中的同名用户在系统表syslogins中的sid不同造成的。解决方法就是在两个数据库上建立同名同sid的用户,具体方法如下:

假设有镜像的服务器是MIR-A和MI-B,要访问镜像数据库的登录账号是tom,使用下面这个方法就可以在MIR-A上创建登录名tom,然后在镜像数据库中创建数据库用户tom并映射到登录名tom
执行下列语句取回tom的sid

select [name], sid from syslogins where [name] = 'tom'
------  -----------------------------------------------
tom 0xD6AABCC8F83E3243A6C3C97F28A4CB55

然后在MIR-B上用下面的语句创建登录名tom

sp_addlogin @loginame = 'tom', @passwd = 'password', @sid = 0xD6AABCC8F83E3243A6C3C97F28A4CB55
Ok,这样就没有问题了。
posted on Friday, April 06, 2007 9:51:10 PM (China Standard Time, UTC+08:00)  #    Comments [1]
# Monday, April 02, 2007

asp.net     在07年春节前拿到了博文视点 赠送的Jesse Liberty和Dan Hurwitz合著的《Programming ASP.NET中文版》第三版。在此向初学asp.net或打算较系统地学习一下asp.net及vs2005方面基础知识的同学们推荐一下这本书。

本书对.NET平台和ASP.NET平台做了详细的介绍,尤其对ASP.NET2.0和VS2005进行了全面的讲解,几乎囊括了ASP.NET在实际应用中的全部重要特性,作者对很多细节也不予吝啬。

书中包含有相当多的实际例子和插图来介绍对应的ASP.NET的特性,并适当地对一些技术点进行了提示:对比了各版本ASP.NET中对应点的差别、开发中的注意事项、应该查阅的资料……(个人对书中的这些提示点很是看重,对初、中级的读者应该很有好处,^_^)

posted on Monday, April 02, 2007 5:01:48 PM (China Standard Time, UTC+08:00)  #    Comments [2]
# Tuesday, January 02, 2007

 将VS2003下的一个Web项目升级到VS2005后,去除明显错误后编译测试运行。某页面发现一个问题:

“/”应用程序中的服务器错误。

分析器错误

说明: 在分析向此请求提供服务所需资源时出错。请检查下列特定分析错误详细信息并适当地修改源文件。

分析器错误信息: 发现不明确的匹配。

这个问题发生原因一般情况是:

aspx页面里面的控件有与您的aspx.cs里的类变量重名(不区分大小写)的ID

那么我发现在代码中有如下的声明:

protected System.Web.UI.WebControls.Label BlogID;
protected System.Web.UI.WebControls.Label blogID;

blogID在前台控件中不存在,仅在cs代码中声明了,因此产生了上述的问题。

 

由此看来虽然,C#等语言中允许我们使用大小写不同来声明不同的变量,但是我们应该尽量避免这样的情况,使用完全不同的名字区分不同的变量为好啊。

posted on Tuesday, January 02, 2007 10:50:23 PM (China Standard Time, UTC+08:00)  #    Comments [2]
# Sunday, December 17, 2006

首先最值得庆祝的是VS2005 SP1在本月15日发布,我在第一时间下载并安装了。该补丁包中最让ASP.Net应用的开发者高兴的恐怕就是Web Application Project的引入了,使用VS2005中文版ASP.Net开发者终于有福了。

而且在VS2005 SP1中的Web Application Project的页面设计视图右键菜单已经有View Code(查看代码)项了。
 

安装VS2005 SP1之前最好先看看这个知识库的925336号文章,不然您可能会安装失败。也就是您最好先做如下图配置:

大家要了解VS2005 SP1可以先看看:

Visual Studio 2005 Service Pack 1

Visual Studio 2005 Service Pack 1 发行说明

第二件比较好的事情就是ASP.Net AJAX(Aatlas)的RC1发布了。

这次的修改内容可以到http://ajax.asp.net/files/AspNet_AJAX_CTP_to_RC_Whitepaper.aspx#link8查看。其中几点重要变化是:

  1. 编译文件由原来的Microsoft.Web.Extensions.dll 变为System.Web.Extensions.dll;
  2. 命名空间也从Microsoft.Web.* 变为 System.Web.*;
  3. registerNamespace修改为Type.registerNamespace();
  4. 附带安装了AJAX-Enabled Web Application项目模板,可以在VS里直接创建AJAX的ASP.Net应用。

PS:RC就是Release Candidate(候选版本)的简称。从微软的惯例来看推出RC版操作系统就代表正式版的操作系统已经离我们不远了,因为微软操作系统的开发步骤是这样的:内部测试->alpha公测->beta公测->RC版->正式版上市;通常微软的RC版本筛选会经历2-3个过程,也就是说微软会推出RC1、RC2或者RC3的操作系统,而随后就是正式版操作系统上市了,因此通常来看RC1版操作系统已经同最终零售版操作系统相差无几了。

posted on Sunday, December 17, 2006 7:06:34 PM (China Standard Time, UTC+08:00)  #    Comments [3]
# Tuesday, November 21, 2006

微软反跨站攻击脚本库 v1.5。此下载包含Microsoft Application Security Anti-Cross Site Scripting Library的分发组件.Anti-Cross Site Scripting Library可以为网站开发人员提供基于Web应用防护,以抵御源自 Cross-Site Scripting (XSS跨站漏洞)的攻击.支持.NET Framework: 2.0, 1.1

下载地址:http://www.microsoft.com/downloads/details.aspx?FamilyID=efb9c819-53ff-4f82-bfaf-e11625130c25&DisplayLang=en

相关文章:http://blogs.msdn.com/kevinlam/archive/2006/07/07/659531.aspx

posted on Tuesday, November 21, 2006 8:22:02 PM (China Standard Time, UTC+08:00)  #    Comments [0]
# Saturday, November 04, 2006
烟台.Net俱乐部网站近几日出现了异常报告,于是调查了一下站点的IIS日志,进行了分析,发现了100次以上的非法访问的IP情况如下:
尝试次数 IP地址 所属地区
4904 211.64.120.192 山东省济南市 山东交通大学
223 74.6.74.159 美国
190 222.80.77.209 新疆喀什市 电信
181 202.108.211.101 北京市 网通
160 222.183.217.187 重庆市江北区 电信ADSL
148 124.156.191.67 中国
112 222.88.189.247 河南省鹤壁市 电信ADSL
100 220.169.248.6 湖南省衡阳市

以这里的第一名211.64.120.192的访问情况为例,其访问的俱乐部网站路径如下:

于是乎把他的IP封锁了,索然这本身没有什么效果,但是对该“黑客”的行为表示痛恨。不过呢其实最痛恨的也不是他啦,最痛恨的是那些疯狂的搜索引擎爬虫,baidu,sogou的爬虫都不是什么好鸟。而且看到很多网站在为这个问题而头痛,希望大家一起努力可以想到一个好的办法来解决这个问题。近期我也会尝试分析和解决这个问题。

posted on Saturday, November 04, 2006 9:33:44 PM (China Standard Time, UTC+08:00)  #    Comments [0]