我应该在遗留 ASP.NET 网站项目中的何处定义 MembershipValidatePasswordEventHandler?

Where should I define a MembershipValidatePasswordEventHandler in a legacy ASP.NET Website Project?

我正在处理一个使用自定义 MembershipProvider 的遗留 ASP.NET 网站项目。我想利用它提供的现有功能来实现密码验证。我想确保以后所有的密码都有一定的长度,并且包含一定数量的大写、小写和非字母数字字符。

到目前为止,我所做的是根据文档 here 中的示例,在网站默认页面的 page_load 函数中注册一个 MembershipValidatePasswordEventHandler。我目前将事件处理程序设置为拒绝一切,只是作为概念证明,而且它有效。尽管如此,考虑到站点中有多个页面,并且默认页面与密码 creation/management.

没有任何关系,注册事件处理程序似乎是一个奇怪的地方
public partial class _Default : System.Web.UI.Page
{
     protected void Page_Load(object sender, EventArgs e)
     {
          Membership.ValidatingPassword += new MembershipValidatePasswordEventHandler(ValidatePasswordEventHandler);
     }
     ...
     public void ValidatePasswordEventHandler(object sender, ValidatePasswordEventArgs e)
     {
          e.Cancel = true;
     }
}

我考虑过在用户创建或更新页面中注册处理程序,但这似乎仍然不合适。我想知道在我开始实施实际密码检查之前是否有更合适的地方来执行此操作,或者这是执行此操作的标准位置吗?

关于更广泛问题的更多上下文,我还尝试修改 web.config 文件中的成员资格提供程序,以根据 this 先前的答案获得此功能的一部分,但是当我提供一个密码无效(小于7个字符)不被拒绝。

<membership defaultProvider="MyMembershipProvider" userIsOnlineTimeWindow="15">
  <providers>
    <add name="MyMembershipProvider" type="MyNamespace.Membership.MyMembershipProvider" applicationName="MyApp" connectionStringName="MyConnectionString" enablePasswordRetrieval="true" enablePasswordReset="true" requiresQuestionAndAnswer="true" writeExceptionsToEventLog="false" passwordFormat="Clear" maxInvalidPasswordAttempts="15" passwordAttemptWindow="10" minRequiredPasswordLength="7"/>
  </providers>
</membership>

更新: This question may also provide some additional justification for why I am interested in the is event handler. The top answer links to this 问题。这个问题的最佳答案提到了做我在这里所做的事情,但说它可能会“在更高的范围内”完成,这更能解决我的问题。 higher/highest 范围在网站项目的上下文中是什么?

解决方法: 我最终使用以下正则表达式修改了 ChangePassword web control's NewPasswordRegularExpression 字段:^(?=.[a-z])(?=.[A-Z])(?=.\d)(?=.[^\da-zA-Z]).{8,}$,而不是实现自定义事件处理程序。

嗯,好的。那么,登录页面当然是在web.config.

中指定的

并且在该登录页面上,您很可能使用了 asp.net“登录”控件。这样登录控件就会有会员提供者-这样说:

<asp:Login ID="Login1" runat="server"  Width="675px" Height="177px" 
 MembershipProvider="MySqlProvider" UserNameLabelText="Username:" 
 FailureText="Login attempt was not successful. Please try again." Font-Size="Small" 
 >

  <LayoutTemplate>
  <div style="margin-left:10px">
            <h>Please enter your Username and Password</h>
            <br />

因此,在您的应用程序中的某个位置创建了会员提供程序,并且将(应该)存在于应用程序中。因此,上面的登录控件将“使用”并使用该会员提供程序 class。而在那个class中,会有这样一个例行的“事情”:

Public Overrides Function ValidateUser(username As String, password As String) As Boolean

    Dim rst As DataTable

    Dim strSQL As String =
             "SELECT * from dbo_ContactName WHERE Email = @user AND PasswordHash = @pass " &
             "AND IsWebActive = 1"

    Dim cmdSQL As New SqlCommand(strSQL)
    cmdSQL.Parameters.Add("@Email", SqlDbType.NVarChar).Value = username
    cmdSQL.Parameters.Add("@pass", SqlDbType.NVarChar).Value = password

    rst = MyRstP(cmdSQL)

因此,登录页面有一个登录控件 - 但它最终会按照上述调用会员提供程序“ValidateUser”。

所以虽然看起来没有“任何”连接,或者指定自定义提供程序如何调用上述验证用户?好吧,登录控件中的标记指定了会员提供者 - 这就是两者的连接方式。

在您的登录页面(带有 asp.net 登录控件的页面),如果一切顺利,则会触发此事件:

Protected Sub Login1_LoggedIn(sender As Object, e As EventArgs) Handles Login1.LoggedIn

    ' this event raises AFTER the user is authenticated
    '
    ' check if user is first time logon
    ' this means that user id = email address

     etc. etc. - do whatever you want for custom logon code.

我不确定以上内容是否有帮助,但它至少说明了登录控件和成员资格提供程序是如何相互连接的。现在,可能从未使用过标准 asp.net 登录控件 - 如果是这种情况,则不会使用登录控件的事件模型。显示登录控件的 属性 sheet,我们看到:

所以登录控件有一组事件 - 但用户的实际验证发生在我假设在此处使用的自定义 sqlmemberShipProivder class 内部。因此 class 应该有一大堆东西,比如 GetUser、ValidateUser、ChangePassword。这里的整个想法是当提供者被正确编写时,然后使用登录控制、更改密码控制等都将为您工作,而不必为此过程建立工具箱中提供的登录控制。

因此,在那个自定义 class (sqlMemberShipProivder) 中,有这样的内容: (还有更多)

我没有看到验证密码用户 - 但有一个 ValidateUser 事件。