明志唯新

ASP.NET 应用中的 Membership 重置密码问题

发表于

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

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

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

MSDN 中有如下描述:

  • ResetPassword 调用 ProviderName 属性所引用的成员资格提供程序的 MembershipProvider.ResetPassword 方法,以将成员资格用户的密码重置为自动生成的新密码。然后将该新密码返回到调用方。
  • 如果 EnablePasswordResetfalse,则成员资格提供程序将返回一个异常。
  • 如果 RequiresQuestionAndAnswertrue,则必须使用以密码提示问题答案作为参数的 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;
    }
}

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

参考浏 览: