ASP.NET 会员更改密码不起作用

发布于 2024-10-18 09:53:43 字数 5426 浏览 5 评论 0原文

我有这段代码,用于在用户单击密码重置按钮时更改用户的密码(使用额外的代码登录 ELMAH,以便我可以尝试找出问题所在)。

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

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

此视图的路径为 /Account/Reset/guid,其中 guid 是用户的 id aspnet 会员数据库。

代码的关键部分是调用 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 < Membership.MinRequiredPasswordLength)
    {
        ErrorSignal.FromCurrentContext().Raise(
            new Exception("ResetPassword - confirm 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 (confirmPassword != newPassword)
    {
        ErrorSignal.FromCurrentContext().Raise(
            new Exception("ResetPassword - new password did not match the confirm password."));
        ModelState.AddModelError("_FORM", "Please enter the same password again.");
        return Json(new { Errors = ModelState.Errors() }, JsonRequestBehavior.AllowGet);
    }

    bool isMatch = ValidationHelper.IsGUID(id);
    if (string.IsNullOrWhiteSpace(id) || !isMatch)
    {
        ErrorSignal.FromCurrentContext().Raise(
            new Exception("ResetPassword - id was not a guid."));
        ModelState.AddModelError("_FORM", "An invalid ID value was passed in through the URL");
    }
    else
    {
        //ID exists and is kosher, see if this user is already approved
        //Get the ID sent in the querystring
        Guid userId = new Guid(id);

        try
        {
            //Get information about the user
            MembershipUser user = Membership.GetUser(userId);
            if (user == null)
            {
                //could not find the user
                ErrorSignal.FromCurrentContext().Raise(
                    new Exception("ResetPassword - could not find user by id " + id));
                ModelState.AddModelError("_FORM", 
                    "The user account can not be found in the system.");
            }
            else
            {
                ErrorSignal.FromCurrentContext().Raise(
                    new Exception("ResetPassword - user is " + user.UserName));
                string pwd = user.ResetPassword();

                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);
                }
                ErrorSignal.FromCurrentContext().Raise(
                    new Exception("ResetPassword 
                    - failed to change the password, for an unknown reason"));
            }
        }
        catch (Exception ex)
        {
            ErrorSignal.FromCurrentContext().Raise(
                new Exception("ResetPassword: " + ex));
            return Json(new { Error = ex.Message + " -> " 
                + ex.InnerException.Message }, JsonRequestBehavior.AllowGet);
        }
    }

    return Json(new { Errors = ModelState.Errors() }, JsonRequestBehavior.AllowGet);
}

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

I have this code for changing a user's password when they click the password reset button (with extra code to log to ELMAH so I can try to figure out what is going wrong).

This is in ASP.NET MVC 2, using the standard aspnet membership provider, with a simple View like this:

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

The route to this view is /Account/Reset/guid, where guid is the user's id in the aspnet membership database.

The key portion of the code is where it calls user.ChangePassword(). You can see that it logs a message when successful. The problem is that for some users, the success message is logged, but they can not log in with the new password. For other users it logs the success message and they can log in.

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);
 }

The full code listing is:

[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 < Membership.MinRequiredPasswordLength)
    {
        ErrorSignal.FromCurrentContext().Raise(
            new Exception("ResetPassword - confirm 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 (confirmPassword != newPassword)
    {
        ErrorSignal.FromCurrentContext().Raise(
            new Exception("ResetPassword - new password did not match the confirm password."));
        ModelState.AddModelError("_FORM", "Please enter the same password again.");
        return Json(new { Errors = ModelState.Errors() }, JsonRequestBehavior.AllowGet);
    }

    bool isMatch = ValidationHelper.IsGUID(id);
    if (string.IsNullOrWhiteSpace(id) || !isMatch)
    {
        ErrorSignal.FromCurrentContext().Raise(
            new Exception("ResetPassword - id was not a guid."));
        ModelState.AddModelError("_FORM", "An invalid ID value was passed in through the URL");
    }
    else
    {
        //ID exists and is kosher, see if this user is already approved
        //Get the ID sent in the querystring
        Guid userId = new Guid(id);

        try
        {
            //Get information about the user
            MembershipUser user = Membership.GetUser(userId);
            if (user == null)
            {
                //could not find the user
                ErrorSignal.FromCurrentContext().Raise(
                    new Exception("ResetPassword - could not find user by id " + id));
                ModelState.AddModelError("_FORM", 
                    "The user account can not be found in the system.");
            }
            else
            {
                ErrorSignal.FromCurrentContext().Raise(
                    new Exception("ResetPassword - user is " + user.UserName));
                string pwd = user.ResetPassword();

                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);
                }
                ErrorSignal.FromCurrentContext().Raise(
                    new Exception("ResetPassword 
                    - failed to change the password, for an unknown reason"));
            }
        }
        catch (Exception ex)
        {
            ErrorSignal.FromCurrentContext().Raise(
                new Exception("ResetPassword: " + ex));
            return Json(new { Error = ex.Message + " -> " 
                + ex.InnerException.Message }, JsonRequestBehavior.AllowGet);
        }
    }

    return Json(new { Errors = ModelState.Errors() }, JsonRequestBehavior.AllowGet);
}

Edit: Adding a bounty to try to get this solved. This is one of the most annoying problems on my issue list, and I have no idea how to proceed.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

冰葑 2024-10-25 09:53:43

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

尝试检查 MembershipUser.IsLockedOut

用户最常被锁定,并且
无法通过验证
ValidateUser 方法,当
已达到最大无效密码尝试次数
在密码尝试窗口内。

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

编辑

您是否还检查了IsApproved?如果用户的设置为 false,则身份验证将失败。

另外,假设默认的成员资格提供程序是指 SqlMembershipProvider,您可以对数据库运行以下查询并确保一切看起来正确吗?

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

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

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

您还可以查看 aspnet_Membership 表中的 PasswordFormat 并根据您使用的格式确保它是正确的值(0 表示清除,1 表示散列,2 表示加密)。

If the user needs to reset his password, there is a chance their account has been locked out from too many invalid attempts. If this is the case, then the password is being reset successfully, but the user cannot log in until the lockout condition is cleared.

Try checking MembershipUser.IsLockedOut:

Users are most commonly locked out and
cannot be validated by the
ValidateUser method when the
MaxInvalidPasswordAttempts is reached
within the PasswordAttemptWindow.

To set this property to false and let
the user try to log in again, you can
use the UnlockUser method.

Edit

Did you also check IsApproved? Authentication will fail is this is false for the user.

Also, assuming by default membership provider, you mean the SqlMembershipProvider, can you run the following query against your database and make sure everything looks correct?

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

Try executing the query before attempting to sign in to verify IsApproved and IsLockedOut are ok. Also note the value for FailedPasswordAttemptCount.

Try signing in, and then run the query again. If signin fails, has the value for FailedPasswordAttemptCount been incremented?

You could also look at PasswordFormat in the aspnet_Membership table and make sure it is the correct value depending on the format you are using (0 for Clear, 1 for Hashed, and 2 for Encrypted).

用心笑 2024-10-25 09:53:43

嗯,我一直使用它

bool MembershipUser.ChangePassword(string oldPassword, string newPassword)

,我从来没有遇到过它返回 true 并且密码未正确更改的问题。
据我所知,您的代码看起来不错。里面充满了 Elmah 的噪音,很难跟上。 (您可能想要删除它或用简单的日志调用替换它,以便更容易理解)。

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

Hmm, I've always used

bool MembershipUser.ChangePassword(string oldPassword, string newPassword)

I've never had an issue with it returning true and the password not being changed correctly.
As fas as I can tell your code looks ok. It is difficult to follow, with all the Elmah noise in there. (you might want to remove it or replace with a simple log call so it's easier to follow).

Verify that the string id that you pass as an argument corresponds to the UserId of the intended user. You might be sending the userId from some other user and changing that users password instead.

且行且努力 2024-10-25 09:53:43

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

那么等等,您是否想通过 Guid 来查找某人?通过这样做,

Guid userId = new Guid(id);

您实际上正在创建一个保证唯一的 ID。所以我的猜测是你永远找不到用户并且你正在为任何人成功重置密码。不可以直接通过你传入的id参数来查找吗?

Edited - following answer is false see comments

So wait are you trying to locate someone by a Guid? By doing

Guid userId = new Guid(id);

You are practically creating a guaranteed to be unique ID. So my guess is you are never finding a user and you are resetting a password successfully for nobody. Can you not just find them by the id parameter you pass in?

祁梦 2024-10-25 09:53:43

这对我有用:

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

<asp:Content ID="HeaderContent" runat="server" ContentPlaceHolderID="HeadContent">
</asp:Content>
<asp:Content ID="BodyContent" runat="server" ContentPlaceHolderID="MainContent">
    <h2>
        Change Password
    </h2>
    <p>
        Use the form below to change your password.
    </p>
    <p>
        New passwords are required to be a minimum of <%= Membership.MinRequiredPasswordLength %> characters in length.
    </p>
    <asp:ChangePassword ID="ChangeUserPassword" runat="server" CancelDestinationPageUrl="~/" EnableViewState="false" RenderOuterTable="false" 
        OnChangedPassword="ChangeUserPassword_ChangedPassword">
        <ChangePasswordTemplate>
            <span class="failureNotification">
                <asp:Literal ID="FailureText" runat="server"></asp:Literal>
            </span>
            <asp:ValidationSummary ID="ChangeUserPasswordValidationSummary" runat="server" CssClass="failureNotification" 
                 ValidationGroup="ChangeUserPasswordValidationGroup"/>
            <div class="accountInfo">
                <fieldset class="changePassword">
                    <legend>Account Information</legend>
                    <p>
                        <asp:Label ID="CurrentPasswordLabel" runat="server" AssociatedControlID="CurrentPassword">Old Password:</asp:Label>
                        <asp:TextBox ID="CurrentPassword" runat="server" CssClass="passwordEntry" TextMode="Password"></asp:TextBox>
                        <asp:RequiredFieldValidator ID="CurrentPasswordRequired" runat="server" ControlToValidate="CurrentPassword" 
                             CssClass="failureNotification" ErrorMessage="Password is required." ToolTip="Old Password is required." 
                             ValidationGroup="ChangeUserPasswordValidationGroup">*</asp:RequiredFieldValidator>
                    </p>
                    <p>
                        <asp:Label ID="NewPasswordLabel" runat="server" AssociatedControlID="NewPassword">New Password:</asp:Label>
                        <asp:TextBox ID="NewPassword" runat="server" CssClass="passwordEntry" TextMode="Password"></asp:TextBox>
                        <asp:RequiredFieldValidator ID="NewPasswordRequired" runat="server" ControlToValidate="NewPassword" 
                             CssClass="failureNotification" ErrorMessage="New Password is required." ToolTip="New Password is required." 
                             ValidationGroup="ChangeUserPasswordValidationGroup">*</asp:RequiredFieldValidator>
                    </p>
                    <p>
                        <asp:Label ID="ConfirmNewPasswordLabel" runat="server" AssociatedControlID="ConfirmNewPassword">Confirm New Password:</asp:Label>
                        <asp:TextBox ID="ConfirmNewPassword" runat="server" CssClass="passwordEntry" TextMode="Password"></asp:TextBox>
                        <asp:RequiredFieldValidator ID="ConfirmNewPasswordRequired" runat="server" ControlToValidate="ConfirmNewPassword" 
                             CssClass="failureNotification" Display="Dynamic" ErrorMessage="Confirm New Password is required."
                             ToolTip="Confirm New Password is required." ValidationGroup="ChangeUserPasswordValidationGroup">*</asp:RequiredFieldValidator>
                        <asp:CompareValidator ID="NewPasswordCompare" runat="server" ControlToCompare="NewPassword" ControlToValidate="ConfirmNewPassword" 
                             CssClass="failureNotification" Display="Dynamic" ErrorMessage="The Confirm New Password must match the New Password entry."
                             ValidationGroup="ChangeUserPasswordValidationGroup">*</asp:CompareValidator>
                    </p>
                </fieldset>
                <p class="submitButton">
                    <asp:Button ID="CancelPushButton" runat="server" CausesValidation="False" CommandName="Cancel" Text="Cancel"/>
                    <asp:Button ID="ChangePasswordPushButton" runat="server" CommandName="ChangePassword" Text="Change Password" 
                         ValidationGroup="ChangeUserPasswordValidationGroup"/>
                </p>
            </div>
        </ChangePasswordTemplate>
        <SuccessTemplate>
            <div class="accountInfo">
                <fieldset class="changePassword">
                    <legend>Password changed</legend>
                        <p>
                            Your password has been changed. A confirmation e-mail has been sent to you.
                        </p>
                </fieldset>
            </div>
        </SuccessTemplate>
    </asp:ChangePassword>
</asp:Content>

This works for me:

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

<asp:Content ID="HeaderContent" runat="server" ContentPlaceHolderID="HeadContent">
</asp:Content>
<asp:Content ID="BodyContent" runat="server" ContentPlaceHolderID="MainContent">
    <h2>
        Change Password
    </h2>
    <p>
        Use the form below to change your password.
    </p>
    <p>
        New passwords are required to be a minimum of <%= Membership.MinRequiredPasswordLength %> characters in length.
    </p>
    <asp:ChangePassword ID="ChangeUserPassword" runat="server" CancelDestinationPageUrl="~/" EnableViewState="false" RenderOuterTable="false" 
        OnChangedPassword="ChangeUserPassword_ChangedPassword">
        <ChangePasswordTemplate>
            <span class="failureNotification">
                <asp:Literal ID="FailureText" runat="server"></asp:Literal>
            </span>
            <asp:ValidationSummary ID="ChangeUserPasswordValidationSummary" runat="server" CssClass="failureNotification" 
                 ValidationGroup="ChangeUserPasswordValidationGroup"/>
            <div class="accountInfo">
                <fieldset class="changePassword">
                    <legend>Account Information</legend>
                    <p>
                        <asp:Label ID="CurrentPasswordLabel" runat="server" AssociatedControlID="CurrentPassword">Old Password:</asp:Label>
                        <asp:TextBox ID="CurrentPassword" runat="server" CssClass="passwordEntry" TextMode="Password"></asp:TextBox>
                        <asp:RequiredFieldValidator ID="CurrentPasswordRequired" runat="server" ControlToValidate="CurrentPassword" 
                             CssClass="failureNotification" ErrorMessage="Password is required." ToolTip="Old Password is required." 
                             ValidationGroup="ChangeUserPasswordValidationGroup">*</asp:RequiredFieldValidator>
                    </p>
                    <p>
                        <asp:Label ID="NewPasswordLabel" runat="server" AssociatedControlID="NewPassword">New Password:</asp:Label>
                        <asp:TextBox ID="NewPassword" runat="server" CssClass="passwordEntry" TextMode="Password"></asp:TextBox>
                        <asp:RequiredFieldValidator ID="NewPasswordRequired" runat="server" ControlToValidate="NewPassword" 
                             CssClass="failureNotification" ErrorMessage="New Password is required." ToolTip="New Password is required." 
                             ValidationGroup="ChangeUserPasswordValidationGroup">*</asp:RequiredFieldValidator>
                    </p>
                    <p>
                        <asp:Label ID="ConfirmNewPasswordLabel" runat="server" AssociatedControlID="ConfirmNewPassword">Confirm New Password:</asp:Label>
                        <asp:TextBox ID="ConfirmNewPassword" runat="server" CssClass="passwordEntry" TextMode="Password"></asp:TextBox>
                        <asp:RequiredFieldValidator ID="ConfirmNewPasswordRequired" runat="server" ControlToValidate="ConfirmNewPassword" 
                             CssClass="failureNotification" Display="Dynamic" ErrorMessage="Confirm New Password is required."
                             ToolTip="Confirm New Password is required." ValidationGroup="ChangeUserPasswordValidationGroup">*</asp:RequiredFieldValidator>
                        <asp:CompareValidator ID="NewPasswordCompare" runat="server" ControlToCompare="NewPassword" ControlToValidate="ConfirmNewPassword" 
                             CssClass="failureNotification" Display="Dynamic" ErrorMessage="The Confirm New Password must match the New Password entry."
                             ValidationGroup="ChangeUserPasswordValidationGroup">*</asp:CompareValidator>
                    </p>
                </fieldset>
                <p class="submitButton">
                    <asp:Button ID="CancelPushButton" runat="server" CausesValidation="False" CommandName="Cancel" Text="Cancel"/>
                    <asp:Button ID="ChangePasswordPushButton" runat="server" CommandName="ChangePassword" Text="Change Password" 
                         ValidationGroup="ChangeUserPasswordValidationGroup"/>
                </p>
            </div>
        </ChangePasswordTemplate>
        <SuccessTemplate>
            <div class="accountInfo">
                <fieldset class="changePassword">
                    <legend>Password changed</legend>
                        <p>
                            Your password has been changed. A confirmation e-mail has been sent to you.
                        </p>
                </fieldset>
            </div>
        </SuccessTemplate>
    </asp:ChangePassword>
</asp:Content>
千年*琉璃梦 2024-10-25 09:53:43

我想知道问题是否在于您在更改密码之前重置了密码。在不深入了解 Membership 类的所有内部结构的情况下,您可以尝试在这两个命令之间添加某种延迟吗?

I wonder if the problem is that you are resetting the password right before you change it. Without getting into all of the internals of the Membership class, could you try putting in some kind of delay between those two commands?

拧巴小姐 2024-10-25 09:53:43

您使用的是哪个 MemberShipProvider?每个用户都一样吗?例如,如果您使用 SqlMembershipProvider 并将enablePasswordReset 设置为 false,它将悄悄地无法更新密码。在本例中,ChangePassword 返回 true,就好像一切顺利一样。

Which MemberShipProvider are you using? Is it the same for every user? For instance, if you use SqlMembershipProvider and set enablePasswordReset to false, it will quietly fail to update the password. ChangePassword, in this case, returns true as if everything went fine.

橙幽之幻 2024-10-25 09:53:43

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

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

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

If you are using the built-in SQLServer based providers take a look at your SQL Stored procs. This is what my default proc looks like:

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

As you can see the update statement could totally fail and the stored proc could return true. I think this is where your errors are probably coming from. Could be locking issues...

无力看清 2024-10-25 09:53:43

嗯,这当然是一件有趣的事情。 “它对某些人有效,对其他人无效”部分确实很奇怪。

这是间歇性问题,还是某些用户总是发生,而其他用户总是不发生

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

你试过这个吗?您可以不断循环,重置+更改密码,直到 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);

注意:这不适用于生产,仅用于测试以查看是否可以解决问题。

Well this is certainly an interesting one. The "it works for some, not for others" part is really bizarre.

Is this an intermittent problem, or does it always occur for certain users, and always not occur for other users?

One of the other people here suggested running ValidateUser(username, newPassword) to confirm that the user could properly authenticate before assuming success.

Have you tried this? You could continuously loop, resetting + changing the password until ValidateUser is successful, perhaps exiting after N failures.

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);

Note: This is not for use in production, just for testing to see if this resolves the problem.

平安喜乐 2024-10-25 09:53:43

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

Are you using 1 webserver or multiple webservers? With multiple servers it could be that the machinekey used for encrypting the password is not the same on al servers.

三岁铭 2024-10-25 09:53:43

您的主要 catch 块本身是否会引发您没有注意到的异常?

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。

Could your main catch block be throwing an exception itself that you haven't noticed?

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

The ex.InnerException.Message statement is not safe because it could throw a NullReferenceException.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文