【问题标题】:Membership Provider ChangePassword Method Return Type ProblemMembership Provider ChangePassword 方法返回类型问题
【发布时间】:2010-12-30 22:35:51
【问题描述】:

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

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

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

因此,即使我知道用户提供的新密码的确切问题,我也无法在网页上显示它,因为我只能从此方法返回真或假,然后更改密码控制接管并根据布尔返回值发挥自己的魔力。我可以连接ChangePassword 控件的OnChangePasswordError 事件以显示静态错误消息,或者我什至可以在发生错误时将此控件的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 eventHandler 的代码:

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 fails without warning http://forums.asp.net/t/983613.aspx

【问题讨论】:

  • 我不会放弃它,但我认为你需要想出一个技巧,比如将它写入数据库之类的。

标签: asp.net-membership membership-provider asp.net-webcontrol


【解决方案1】:

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

【讨论】:

    【解决方案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;
            } 
    

    【讨论】:

      【解决方案3】:

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

      注意:我没有将其保存在数据库或 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";
      }
      

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

      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方法并再次返回错误.但我已经将FailureText 属性设置为第一次调用中响应返回的描述性错误,这是我的目标。在我的情况下,我不介意两个方法调用。您的情况可能不同。

      希望这对某人有所帮助!

      【讨论】:

        【解决方案4】:

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

        【讨论】:

          猜你喜欢
          • 2013-04-18
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-12-14
          • 1970-01-01
          • 2018-11-02
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多