ASP.NET成员身份更改密码无效

我有这个代码,当他们点击密码重置按钮时更改用户的密码(有额外的代码登录到ELMAH,所以我可以试着弄清楚出了什么问题)。

这是在ASP.NET MVC 2中,使用标准的aspnet成员资格提供程序,使用这样的简单视图:

New Password: ______ Confirm Password: ______ [Reset] [Cancel] 

此视图的路径是/Account/Reset/guid ,其中guid是aspnet成员资格数据库中的用户ID。

代码的关键部分是它调用user.ChangePassword() 。 您可以看到它在成功时记录消息。 问题是对于某些用户,会记录成功消息,但他们无法使用新密码登录。 对于其他用户,它会记录成功消息,并且他们可以登录。

 if (user.ChangePassword(pwd, confirmPassword)) { ErrorSignal.FromCurrentContext().Raise( new Exception("ResetPassword - changed successfully!")); return Json(new { Msg = "You have reset your password successfully." }, JsonRequestBehavior.AllowGet); } 

完整的代码清单是:

 [HttpPost] public JsonResult ResetPassword(string id, string newPassword, string confirmPassword) { ErrorSignal.FromCurrentContext().Raise(new Exception("ResetPassword started for " + id)); ViewData["PasswordLength"] = Membership.MinRequiredPasswordLength; if (string.IsNullOrWhiteSpace(newPassword)) { ErrorSignal.FromCurrentContext().Raise( new Exception("ResetPassword - new password was blank.")); ModelState.AddModelError("_FORM", "Please enter a new password."); return Json(new { Errors = ModelState.Errors() }, JsonRequestBehavior.AllowGet); } if (newPassword.Length < Membership.MinRequiredPasswordLength) { ErrorSignal.FromCurrentContext().Raise( new Exception("ResetPassword - new password was less than minimum length.")); ModelState.AddModelError("_FORM", string.Format("The password must be at least {0} characters long.", Membership.MinRequiredPasswordLength)); return Json(new { Errors = ModelState.Errors() }, JsonRequestBehavior.AllowGet); } if (string.IsNullOrWhiteSpace(confirmPassword)) { ErrorSignal.FromCurrentContext().Raise( new Exception("ResetPassword - confirm password was blank.")); ModelState.AddModelError("_FORM", "Please enter the same new password in the confirm password textbox."); return Json(new { Errors = ModelState.Errors() }, JsonRequestBehavior.AllowGet); } if (confirmPassword.Length  " + ex.InnerException.Message }, JsonRequestBehavior.AllowGet); } } return Json(new { Errors = ModelState.Errors() }, JsonRequestBehavior.AllowGet); } 

编辑:添加赏金以尝试解决此问题。 这是我的问题列表中最烦人的问题之一,我不知道如何继续。

如果用户需要重置密码,则他们的帐户有可能被锁定,因为无效的尝试次数过多。 如果是这种情况,则密码正在成功重置,但用户无法登录,直到锁定条件被清除。

尝试检查MembershipUser.IsLockedOut :

在PasswordAttemptWindow中达到MaxInvalidPasswordAttempts时,用户最常被锁定,并且无法通过ValidateUser方法进行validation。

要将此属性设置为false并让用户尝试再次登录,可以使用UnlockUser方法。

编辑

你也检查过IsApproved吗? 身份validation将失败,这对用户来说是false的。

此外,假设默认情况下成员资格提供程序,您的意思是SqlMembershipProvider,您是否可以针对您的数据库运行以下查询并确保一切正常?

 select IsApproved, IsLockedOut, FailedPasswordAttemptCount from aspnet_Membership where ApplicationId = @yourApplicationId and UserId = @userId 

尝试登录以validationIsApprovedIsLockedOut是否正常之前,请尝试执行查询。 另请注意FailedPasswordAttemptCount的值。

尝试登录,然后再次运行查询。 如果登录失败, FailedPasswordAttemptCount的值是否已递增?

您还可以在aspnet_Membership表中查看PasswordFormat并确保它是正确的值,具体取决于您使用的格式(0表示清除,1表示Hashed,2表示加密)。

嗯,我一直都在使用

 bool MembershipUser.ChangePassword(string oldPassword, string newPassword) 

我从来没有遇到过它返回true并且密码没有正确更改的问题。 我可以告诉您的代码看起来不错。 很难跟上,那里有所有的Elmah噪音。 (您可能希望将其删除或替换为简单的日志调用,以便更容易理解)。

validation作为参数传递的字符串ID是否与目标用户的UserId相对应。 您可能正在从其他用户发送userId并改为更改该用户密码。

编辑 – 以下答案是错误的,请参阅评论

所以你要等一下Guid定位某人吗? 通过做

 Guid userId = new Guid(id); 

您实际上创建了一个保证唯一ID。 所以我的猜测是你永远找不到用户而且你正在为没人成功重置密码。 您是否可以通过传入的id参数找到它们?

这对我有用:

 <%@ Page Title="Change Password" Language="C#" MasterPageFile="~/Site.master" AutoEventWireup="true" CodeBehind="ChangePassword.aspx.cs" Inherits="WebPages.Account.ChangePassword" %>    

Change Password

Use the form below to change your password.

New passwords are required to be a minimum of <%= Membership.MinRequiredPasswordLength %> characters in length.

Account Information

Old Password: *

New Password: *

Confirm New Password: * *

Password changed

Your password has been changed. A confirmation e-mail has been sent to you.

我想知道问题是你在更改之前是否正在重置密码。 如果没有进入Membership类的所有内部,你能尝试在这两个命令之间加入某种延迟吗?

你使用哪个MemberShipProvider? 每个用户都一样吗? 例如,如果您使用SqlMembershipProvider并将enablePasswordReset设置为false,则它将悄然无法更新密码。 在这种情况下,ChangePassword返回true,好像一切都很顺利。

如果您使用内置的基于SQLServer的提供程序,请查看SQL存储过程。 这是我的默认proc看起来像:

 ALTER PROCEDURE dbo.aspnet_Membership_SetPassword @ApplicationName nvarchar(256), @UserName nvarchar(256), @NewPassword nvarchar(128), @PasswordSalt nvarchar(128), @CurrentTimeUtc datetime, @PasswordFormat int = 0 AS BEGIN DECLARE @UserId uniqueidentifier SELECT @UserId = NULL SELECT @UserId = u.UserId FROM dbo.aspnet_Users u, dbo.aspnet_Applications a, dbo.aspnet_Membership m WHERE LoweredUserName = LOWER(@UserName) AND u.ApplicationId = a.ApplicationId AND LOWER(@ApplicationName) = a.LoweredApplicationName AND u.UserId = m.UserId IF (@UserId IS NULL) RETURN(1) UPDATE dbo.aspnet_Membership SET Password = @NewPassword, PasswordFormat = @PasswordFormat, PasswordSalt = @PasswordSalt, LastPasswordChangedDate = @CurrentTimeUtc WHERE @UserId = UserId RETURN(0) END 

如您所见,update语句可能完全失败,存储过程可能返回true。 我认为这是你的错误可能来自的地方。 可能是锁定问题……

那肯定是一个有趣的。 “它适用于某些人,而不适用于其他人”部分非常奇怪。

这是一个间歇性问题,还是某些用户总是会出现问题,而其他用户总是不会出现这种问题

这里的其中一个人建议运行ValidateUser(username, newPassword)以确认用户在假设成功之前可以正确地进行身份validation。

你试过这个吗? 您可以连续循环,重置+更改密码,直到ValidateUser成功,可能在N次失败后退出。

 bool success = false; int numAttempts = 0; do { string pwd = user.ResetPassword(); if (user.ChangePassword(pwd, confirmPassword)) { success = Membership.ValidateUser(user.UserName, pwd); } numAttempts++; } while(numAttempts < 5 && !success); 

注意:这不是用于生产,只是为了测试是否能解决问题。

您使用的是1个网络服务器还是多个网络服务器? 对于多个服务器,可能是用于加密密码的机器密钥在al服务器上是不同的。

您的主要捕获块可能会抛出您未注意到的exception吗?

 catch (Exception ex) { ErrorSignal.FromCurrentContext().Raise(new Exception("ResetPassword: " + ex)); return Json(new { Error = ex.Message + " -> " + ex.InnerException.Message }, JsonRequestBehavior.AllowGet); } 

ex.InnerException.Message语句不安全,因为它可能抛出NullReferenceException。