2

我们已经实施了自定义成员资格提供程序,并在使用此提供程序的网页上设置了更改密码控制。此成员资格提供程序类中的 ChangePassword 方法通过连接到外部 Web 服务来检查有关密码强度和有效性的一些业务逻辑。如果有任何问题(长度问题、需要特殊字符等),Web 服务能够准确返回新密码的问题。

现在,必须由自定义提供程序覆盖的 ChangePassword 方法的签名是:

public override bool ChangePassword(string username, string oldPassword, string newPassword)

因此,即使我知道用户提供的新密码的确切问题,我也无法在网页上显示它,因为我只能从此方法返回真或假,然后更改密码控制接管并自己执行魔术取决于布尔返回值。我可以连接控件的OnChangePasswordError事件ChangePassword以显示静态错误消息,或者我什至可以FailureText在发生错误时将此控件的属性设置为一些硬编码字符串,但我无法向用户提供究竟是什么错误使用他们提供的密码。

protected void OnPasswordChangeError(object sender, EventArgs e)
        {
            throw new MembershipPasswordException("Tell user what exactly is wrong with the password they supplied");
        }

该类MembershipProvider有一个ValidatingPassword事件,在更改密码之前引发,我可以通过检查密码是否符合条件来抛出异常,但该异常似乎仍然没有传递给 ChangePassword 控件。这是 ValidatingPassword 事件处理程序的代码:

void MyMembershipProvider_ValidatingPassword(object sender, ValidatePasswordEventArgs e)
        {
           //if password not valid
           e.Cancel = true;
           e.FailureInformation = new MembershipPasswordException();
           e.FailureInformation;           
        }  

如何将特定信息从 Membership 提供程序类的 ChangePassword 方法发送到 ChangePassword 控件,以向用户显示正确的、非静态/硬编码的密码更改错误消息?有没有办法将 ValidatePasswordEventArgs 连接到 OnChangePassword 方法的 EventHandler 中的 EventArgs,以便我可以在 ChangePassword 控件中获取 FailureInformation?

从我最初的研究来看,这似乎是不可能的。虽然我觉得MS团队不会忽视这一点,应该有办法。

几点建议:

MembershipUser.ChangePassword 在没有警告的情况下失败 http://forums.asp.net/t/983613.aspx

4

4 回答 4

2

好的,所以我终于想出了一个解决方法。它不是最干净的,但我能想出或找到的唯一一个接近默认情况下应该包含的内容。

注意:我没有选择将其保存在数据库或 cookie 中。

我创建了一个 ChangePasswordNew与该方法具有相同行为的MembershipProvider ChangePassword方法,但返回的是字符串而不是布尔值。所以我的新方法看起来像这样:

public string ChangePasswordNew(string username, string oldPassword, string newPassword)
{
    //if password rules met, change password but do not return bool as MembershipProvider method does, 
    //return Success or the exact error for failure instead
    if(passwordChangeRequirementsMet == true)  
    {
        //change the password
        return "success";
    }
    else          
        return "exact reason why password cannot be changed";
}

现在,订阅控件的onPasswordChanging事件:ChangePassword

protected void PasswordIsChanging(object sender, LoginCancelEventArgs e)
{
try
    {
      string response = Provider.ChangePasswordNew(username, currentPass, newPass);
      if(response != "success")
      {
        changePwdCtrl.FailureText = response;
      }
     else
    {
    //cancel call to the default membership provider method that will attempt to
    //change the password again. Instead, replicate the 'steps' of AttemptChangePassword(), 
    //an internal method of the ChangePassword control.
    //Performing all the steps instead of calling the method because just calling method
    //does not work for some reason

    e.Cancel = true;
    FormsAuthentication.SetAuthCookie(username, false);
    OnPasswordChanged(sender, e);

    MethodInfo successMethodInfo = changePwdCtrl.GetType().GetMethod("PerformSuccessAction",                                    BindingFlags.NonPublic | BindingFlags.Instance);
    successMethodInfo.Invoke(changePwdCtrl, new object[] { "", "", changePwdCtrl.NewPassword });
}
}
catch(Exception ex)
{
    LogException(ex);
    throw;
}

}

注意:在这种情况下,如果修改密码出错,即响应不是“成功”,ChangePassword仍然会调用 Memebership Provider 方法并再次返回错误。但是我已经将该FailureText属性设置为从第一次调用中的响应返回的描述性错误,这是我的目标。在我的情况下,我不介意两个方法调用。你的情况可能不同。

希望这对某人有帮助!

于 2010-02-22T23:00:49.170 回答
2

您可以改为这样做,这样您就不会调用 changepassword 方法两次。

if(response != "success") 
      { 
       e.Cancel = true;
((Literal)changePwdCtrl.ChangePasswordTemplateContainer.FindControl("FailureText")).Text = response;
      }

我创建了一个自定义的membershipprovider 类来处理这个问题,membership 类中的changepassword 方法会抛出特定消息的错误消息,然后我将其返回给更改密码控件的控件文字。

protected void ChangePassword1_ChangingPassword(object sender, LoginCancelEventArgs e)
    {
        try
        {
            ChangePassword c = (ChangePassword)sender;

            MembershipUser mu = Membership.GetUser(c.UserName);

            bool response;

            try
            {
                response = mu.ChangePassword(c.CurrentPassword, c.NewPassword);
            }
            catch (Exception ex)
            {

                response = false;
                e.Cancel = true;
                //ChangePassword1.ChangePasswordFailureText = ex.Message;
                //ChangePassword1_ChangePasswordError(sender, e);      
                //((Literal)ChangePassword1.ChangePasswordTemplateContainer.FindControl("FailureText")).Visible = true;
                ((Literal)ChangePassword1.ChangePasswordTemplateContainer.FindControl("FailureText")).Text = ex.Message;

            }

            if (response)
            {        
                //cancel call to the default membership provider method that will attempt to 
                //change the password again. Instead, replicate the 'steps' of AttemptChangePassword(),  
                //an internal method of the ChangePassword control. 
                //Performing all the steps instead of calling the method because just calling method 
                //does not work for some reason 

                e.Cancel = true;
                FormsAuthentication.SetAuthCookie(c.UserName, false);
                ChangePassword1_ChangedPassword(sender, e);
                MethodInfo successMethodInfo = ChangePassword1.GetType().GetMethod("PerformSuccessAction", BindingFlags.NonPublic | BindingFlags.Instance);
                successMethodInfo.Invoke(ChangePassword1, new object[] { "", "", ChangePassword1.NewPassword });

            }
        }
        catch (Exception ex)
        {            
            throw;
        } 
于 2010-10-24T04:34:54.527 回答
1

有一次,我需要从提供者那里传递信息,最后只设置了一个 cookie,然后返回你的 bool,以便在通话的另一端接听。工作得很好。

于 2010-02-17T23:29:32.307 回答
0

我相信更简洁的解决方法是让 ChangePassword 方法抛出异常。异常包含错误消息!

于 2016-12-16T03:21:45.813 回答