会员提供商 ChangePassword 方法返回类型问题

发布于 2024-08-15 21:09:35 字数 1868 浏览 8 评论 0原文

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

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

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

因此,即使我知道用户提供的新密码的确切问题,我也无法在网页上显示它,因为我只能返回此方法的 true 或 false 以及更改密码控件然后接管并根据布尔返回值发挥其自身的魔力。我可以连接 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 事件处理程序的代码:

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

We have implemented a Custom Membership provider and have a change password control on a webpage that uses this provider. The ChangePassword method in this membership provider class checks some business logic about password strength and validity by connecting to an external webservice. The webservice has the ability to return exactly what is wrong with the new password if any (length problems, special character required etc.).

Now, the signature of the ChangePassword method that has to be overriden by a custom provider is:

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

So even though I know the exact problem with the new password the user supplies, I am not able to display it on the webpage because I can only return a true or false from this method and the change password control then takes over and does its own magic depending on the boolean return value. I can hook up the OnChangePasswordError event of the ChangePassword control to show a static error message, or I can even setup the FailureText property of this control to some hard-coded string when an error occurs, but I am unable to provide to the user what exactly is wrong with the password they supplied.

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

The MembershipProvider class has a ValidatingPassword event, that is raised BEFORE the password is changed, and I can throw an exception here by checking if the password meets the criteria, but still that exception does not seem to be passed to the ChangePassword control. Here is the code for the ValidatingPassword eventHandler:

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

how to send specific information from the ChangePassword method of the Membership provider class to the ChangePassword control to display the correct, non static/hardcoded password change error messages to the user? Is there a way to hook up the ValidatePasswordEventArgs to the EventArgs in the EventHandler for the OnChangePassword method so that I can get the FailureInformation in the ChangePassword control?

From my initial research this does not seem to be possible. Though I feel that the MS team would not have overlooked this and there should be a way.

A few pointers:

MembershipUser.ChangePassword fails without warning
http://forums.asp.net/t/983613.aspx

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

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

发布评论

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

评论(4

失而复得 2024-08-22 21:09:36

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

注意:我无法选择将其保存在数据库或 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;
}

}

注意: 在这种情况下,如果有密码更改时发生错误,即响应不是“成功”,Memebership Provider ChangePassword 方法仍将被调用并再次返回错误。但我已经将 FailureText 属性设置为第一次调用中响应返回的描述性错误,这是我的目标。在我的例子中,我不介意两次方法调用。您的情况可能有所不同。

希望这对某人有帮助!

OK, so I finally figured a workaround. It is not the cleanest, but the only one I could come up with or found anywhere that was close to what should have been inclued by default.

Note: I did not have the option to persist this in a database or a cookie.

I created a ChangePasswordNew method that has the same behavior as the MembershipProvider ChangePassword method, but returns string instead of bool. So my new method would look like this:

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

Now, subscribe to the onPasswordChanging event of the ChangePassword Control:

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

}

Note: In this case, if there is an error on password change, i.e. response is not "success", the Memebership Provider ChangePassword method will still be called and will return an error again. But I am already setting the FailureText property to the descriptive error returned from response in the first call, which was my objective. I did not mind two method calls in my case. Your case may be different.

Hope this helps someone!

清眉祭 2024-08-22 21:09:36

您可以这样做,这样您就不会两次调用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;
        } 

You can do this instead, that way you are not calling the changepassword method twice.

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

I created a custom membershipprovider class that handles this, the changepassword method in the membership class throws and error message of the specific message and I return that back to the control literal of the change password control.

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;
        } 
玉环 2024-08-22 21:09:36

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

At one time I needed to pass info out of a provider and ended up just setting a cookie before returning your bool to be picked up on the other end of the call. Worked fine.

時窥 2024-08-22 21:09:36

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

I believe a cleaner workaround is for the ChangePassword method to throw an exception. The exception contains the error message!

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