针对成员身份用户存储验证用户凭据 (C#)

作者 :Scott Mitchell

注意

自本文撰写以来,ASP.NET 成员资格提供程序已被 ASP.NET Identity 取代。 强烈建议更新应用以使用 ASP.NET 标识 平台,而不是本文撰写时介绍的成员资格提供程序。 ASP.NET 标识比 ASP.NET 成员身份系统具有许多优势,包括:

  • 性能更好
  • 改进了可扩展性和可测试性
  • 支持 OAuth、OpenID Connect 和双因素身份验证
  • 基于声明的标识支持
  • 更好地与 ASP.Net Core 的互操作性

下载代码下载 PDF

在本教程中,我们将了解如何使用编程方式和登录控件针对成员资格用户存储验证用户的凭据。 我们还将介绍如何自定义登录控件的外观和行为。

简介

前面的教程中 ,我们了解了如何在成员资格框架中创建新的用户帐户。 我们首先查看了如何通过 Membership 类的 CreateUser 方法以编程方式创建用户帐户,然后使用 CreateUserWizard Web 控件进行了检查。 但是,登录页当前根据用户名和密码对的硬编码列表验证提供的凭据。 我们需要更新登录页的逻辑,以便它针对成员资格框架的用户存储验证凭据。

与创建用户帐户非常类似,可以通过编程或声明方式验证凭据。 成员资格 API 包含一个方法,用于以编程方式针对用户存储验证用户的凭据。 ASP.NET 随登录 Web 控件一起提供,该控件呈现用户界面,其中包含用户名和密码的文本框以及用于登录的按钮。

在本教程中,我们将了解如何使用编程方式和登录控件针对成员资格用户存储验证用户的凭据。 我们还将介绍如何自定义登录控件的外观和行为。 让我们开始吧!

步骤 1:针对成员资格用户存储验证凭据

对于使用表单身份验证的网站,用户通过访问登录页并输入其凭据登录到网站。 然后,将这些凭据与用户存储进行比较。 如果它们有效,则向用户授予 Forms 身份验证票证,该票证是指示访问者的身份和真实性的安全令牌。

若要根据 Membership 框架验证用户,请使用 Membership 类的 ValidateUser 方法。 方法 ValidateUser 采用两个输入参数 - usernamepassword ,并返回一个布尔值,该值指示凭据是否有效。 与 CreateUser 我们在上一教程中介绍的方法一样, ValidateUser 方法将实际验证委托给配置的成员资格提供程序。

SqlMembershipProvider通过aspnet_Membership_GetPasswordWithFormat存储过程获取指定用户的密码来验证提供的凭据。 回想一下, SqlMembershipProvider 使用三种格式之一存储用户的密码:清除、加密或哈希。 aspnet_Membership_GetPasswordWithFormat存储过程以原始格式返回密码。 对于加密或哈希密码, SqlMembershipProvider 将传入ValidateUser方法的值转换为password其等效的加密或哈希状态,然后将其与从数据库返回的值进行比较。 如果数据库中存储的密码与用户输入的格式化密码匹配,则凭据有效。

让我们更新登录页 (~/Login.aspx) ,以便针对成员资格框架用户存储验证提供的凭据。 我们在 Forms 身份验证概述教程中创建了此登录页,创建了一个界面,其中包含用户名和密码的两个 TextBox、一个“记住我”复选框和一个“登录”按钮, (见图 1) 。 该代码根据 scott/password、Jisun/password 和 Sam/password) (用户名和密码对的硬编码列表验证输入的凭据。

登录页的界面包括两个文本框、一个 CheckBoxList 和一个按钮

图 1:登录页的界面包括两个文本框、一个 CheckBoxList 和一个按钮 (单击以查看全尺寸图像)

登录页的用户界面可以保持不变,但我们需要将登录按钮的 Click 事件处理程序替换为针对成员资格框架用户存储验证用户的代码。 更新事件处理程序,使其代码如下所示:

protected void LoginButton_Click(object sender, EventArgs e)
{
    // Validate the user against the Membership framework user store
    if (Membership.ValidateUser(UserName.Text, Password.Text))
    {
        // Log the user into the site
        FormsAuthentication.RedirectFromLoginPage(UserName.Text, RememberMe.Checked);
    }
    // If we reach here, the user's credentials were invalid
    InvalidCredentialsMessage.Visible = true;
}

此代码非常简单。 首先调用 Membership.ValidateUser 方法,传入提供的用户名和密码。 如果该方法返回 true,则用户将通过 FormsAuthentication 类的 RedirectFromLoginPage 方法登录到站点。 (如表单身份验证概述教程中所述FormsAuthentication.RedirectFromLoginPage 会创建表单身份验证票证,然后将用户重定向到相应的页面。) 如果凭据无效,InvalidCredentialsMessage则会显示标签,通知用户其用户名或密码不正确。

就是这么简单!

若要测试登录页是否按预期工作,请尝试使用在上一教程中创建的某个用户帐户登录。 或者,如果尚未创建帐户,请继续从 ~/Membership/CreatingUserAccounts.aspx 页面创建一个帐户。

注意

当用户输入其凭据并提交登录页表单时,凭据(包括密码)通过 Internet 以 纯文本形式传输到 Web 服务器。 这意味着任何嗅探网络流量的黑客都可以看到用户名和密码。 为防止这种情况,必须使用 安全套接字层 (SSL) 加密网络流量。 这将确保凭据 (以及整个页面的 HTML 标记) 从离开浏览器的那一刻起加密,直到 Web 服务器收到它们。

成员资格框架如何处理无效登录尝试

当访问者到达登录页并提交其凭据时,其浏览器会向登录页发出 HTTP 请求。 如果凭据有效,HTTP 响应会将身份验证票证包含在 Cookie 中。 因此,试图侵入您的网站的黑客可能会创建一个程序,该程序会使用有效的用户名和密码猜测将 HTTP 请求详尽地发送到登录页面。 如果密码猜测正确,登录页将返回身份验证票证 Cookie,此时程序知道它偶然发现了有效的用户名/密码对。 通过暴力破解,此类程序可能会偶然发现用户的密码,尤其是在密码较弱的情况下。

为了防止此类暴力攻击,成员资格框架会在特定时间段内出现一定数量的失败登录尝试时锁定用户。 可以通过以下两个成员资格提供程序配置设置来配置确切的参数:

  • maxInvalidPasswordAttempts - 指定在帐户被锁定之前的时间段内允许用户进行多少次无效密码尝试。默认值为 5。
  • passwordAttemptWindow - 指示指定的无效登录尝试次数将导致帐户被锁定的时间段(以分钟为单位)。默认值为 10。

如果用户已被锁定,则在管理员解锁其帐户之前,她无法登录。 当用户被锁定时, ValidateUser 方法 将始终 返回 false,即使提供了有效的凭据。 虽然此行为可降低黑客通过暴力破解方法闯入网站的可能性,但最终可能会锁定一个只忘记密码或意外打开 Caps Lock 或键入日期不佳的有效用户。

遗憾的是,没有用于解锁用户帐户的内置工具。 若要解锁帐户,可以直接修改数据库(更改 IsLockedOut 相应用户帐户的表中的 字段 aspnet_Membership ),或者创建一个基于 Web 的界面,该界面列出锁定的帐户以及用于解锁这些帐户的选项。 我们将在未来的教程中探讨如何创建管理接口来完成与用户帐户和角色相关的常见任务。

注意

方法的 ValidateUser 一个缺点是,当提供的凭据无效时,它不提供任何解释原因。 凭据可能无效,因为用户存储中没有匹配的用户名/密码对,或者用户尚未获得批准,或者用户已被锁定。在步骤 4 中,我们将了解如何在用户登录尝试失败时向用户显示更详细的消息。

步骤 2:通过登录 Web 控件收集凭据

登录 Web 控件呈现的默认用户界面非常类似于我们在表单身份验证概述教程中创建的默认用户界面。 使用 Login 控件可以节省创建接口来收集访问者凭据的工作。 此外,如果提交的凭据) 有效,则 Login 控件会自动将用户登录 (,从而无需编写任何代码。

让我们更新 Login.aspx,将手动创建的接口和代码替换为 Login 控件。 首先删除 中的 Login.aspx现有标记和代码。 可以将其直接删除,也可以直接将其注释掉。若要注释掉声明性标记,请使用 和 --%> 分隔符将其<%--括起来。 您可以手动输入这些分隔符,或者,如图 2 所示,您可以选择要注释掉的文本,然后单击工具栏中的“注释掉所选行”图标。 同样,可以使用“注释掉所选行”图标来注释掉代码隐藏类中的选定代码。

注释掉 Login.aspx 中的现有声明性标记和源代码

图 2:注释掉 (中的 Login.aspx 现有声明性标记和源代码 单击以查看全尺寸图像)

注意

在 Visual Studio 2005 中查看声明性标记时,“注释掉所选行”图标不可用。 如果不使用 Visual Studio 2008,则需要手动添加 <%----%> 分隔符。

接下来,将一个 Login 控件从“工具箱”拖到页面上,并将其 ID 属性设置为 myLogin。 此时,屏幕应类似于图 3。 请注意,登录控件的默认界面包括用户名和密码的 TextBox 控件、下一次 CheckBox 时记住我以及登录按钮。 还有 RequiredFieldValidator 两个 TextBox 的控件。

将登录控件添加到页面

图 3:将登录控件添加到页面 (单击以查看全尺寸图像)

大功告成! 单击登录控件的“登录”按钮时,将发生回发,并且 Login 控件将调用 Membership.ValidateUser 方法,并传入输入的用户名和密码。 如果凭据无效,则 Login 控件会显示一条消息,指出存在这种情况。 但是,如果凭据有效,则 Login 控件会创建表单身份验证票证并将用户重定向到相应的页面。

Login 控件使用四个因素来确定在成功登录时将用户重定向到的相应页面:

  • 登录控件是否位于登录页上,如 loginUrl 表单身份验证配置中的设置所定义;此设置的默认值为 Login.aspx
  • 是否存在 ReturnUrl querystring 参数
  • Login 控件DestinationUrl 属性的值
  • 表单 defaultUrl 身份验证配置设置中指定的值;此设置的默认值为 Default.aspx

图 4 描述了 Login 控件如何使用这四个参数得出其适当的页面决策。

Login 控件使用四个参数来得出其适当的页面决策。

图 4:将登录控件添加到页面 (单击以查看全尺寸图像)

花点时间测试登录控件,方法是通过浏览器访问站点,并在成员资格框架中以现有用户身份登录。

Login 控件的呈现接口高度可配置。 有许多属性会影响其外观:更重要的是,Login 控件可以转换为模板,以便精确控制用户界面元素的布局。 此步骤的其余部分将检查如何自定义外观和布局。

自定义登录控件的外观

Login 控件的默认属性设置呈现一个用户界面,其中包含标题 (“登录) ”、“TextBox”和“标签”控件(用于用户名和密码输入),以及“下次记住我 CheckBox”以及“登录”按钮。 这些元素的外观都可以通过 Login 控件的众多属性进行配置。 此外,还可以通过设置一两个属性来添加其他用户界面元素(例如指向用于创建新用户帐户的页面的链接)。

让我们花点时间来了解登录控件的外观。 Login.aspx由于页面顶部已有显示 Login 的文本,因此登录控件的标题是多余的。 因此,清除 TitleText 属性值 以删除 Login 控件的标题。

可以通过 和 属性分别自定义UserNameLabelText两个 TextBox 控件左侧的“用户名:”和PasswordLabelText“密码:标签”。 让我们将“用户名:标签”更改为“用户名:”。 标签和 TextBox 样式分别通过 LabelStyleTextBoxStyle 属性进行配置。

可通过 Login 控件 RememberMeText property的 设置 CheckBox 的 Text 属性,并且其默认选中状态可通过 RememberMeSet property 默认为 False) (可配置。 继续将 属性设置为 RememberMeSet True,以便默认选中“下次记住我”CheckBox。

Login 控件提供两个属性,用于调整其用户界面控件的布局。 指示 TextLayout property “用户名: ”和“密码: 标签”是否显示在其相应 TextBox 的左侧, (默认) 或上方。 指示 Orientation property 用户名和密码输入是垂直 (另一个) 还是水平放置。 我要将这两个属性设置为默认值,但建议尝试将这两个属性设置为其非默认值,以查看结果效果。

注意

在下一部分配置登录控件的布局中,我们将介绍如何使用模板定义布局控件用户界面元素的精确布局。

通过将 和 CreateUserUrl 属性设置为CreateUserText“尚未注册”来包装 Login 控件的属性设置? 创建帐户! 和 ~/Membership/CreatingUserAccounts.aspx分别。 这会向 Login 控件的接口添加一个超链接,指向我们在上一教程中创建的页面。 Login 控件的 HelpPageTextHelpPageUrl 属性PasswordRecoveryTextPasswordRecoveryUrl 属性 的工作方式相同,呈现指向帮助页和密码恢复页的链接。

进行这些属性更改后,Login 控件的声明性标记和外观应类似于图 5 所示。

登录控件的属性值决定了其外观

图 5:登录控件的属性值决定了其外观 (单击以查看全尺寸图像)

配置登录控件的布局

登录 Web 控件的默认用户界面在 HTML <table>中布局接口。 但是,如果需要对呈现的输出进行更精细的控制,该怎么办? 也许我们想用一系列<div>标记替换 <table> 。 或者,如果应用程序需要其他凭据进行身份验证,该怎么办? 例如,许多金融网站不仅要求用户提供用户名和密码,还要求用户提供个人标识号 (PIN) 或其他识别信息。 无论原因是什么,都可以将 Login 控件转换为模板,我们可以从模板中显式定义接口的声明性标记。

我们需要执行两项操作才能更新 Login 控件以收集其他凭据:

  1. 更新 Login 控件的接口,以包含 Web 控件 () 以收集其他凭据。
  2. 重写登录控件的内部身份验证逻辑,以便仅当用户的用户名和密码有效且其附加凭据有效时才会进行身份验证。

若要完成第一个任务,我们需要将 Login 控件转换为模板并添加必要的 Web 控件。 至于第二个任务,可以通过为控件的事件创建事件处理程序来取代 Login 控件的Authenticate身份验证逻辑。

让我们更新登录控件,以便它提示用户输入其用户名、密码和电子邮件地址,并且仅当用户提供的电子邮件地址与其在文件中的电子邮件地址匹配时,才会对用户进行身份验证。 首先需要将 Login 控件的接口转换为模板。 从登录控件的智能标记中,选择“转换为模板”选项。

将登录控件转换为模板

图 6:将登录控件转换为模板 (单击以查看全尺寸图像)

注意

若要将 Login 控件还原到其预模板版本,请单击控件的智能标记中的“重置”链接。

将 Login 控件转换为模板时,会将 添加到 LayoutTemplate 控件的声明性标记中,其中包含定义用户界面的 HTML 元素和 Web 控件。 如图 7 所示,将控件转换为模板会从属性窗口中删除许多属性,例如 TitleTextCreateUserUrl等,因为使用模板时会忽略这些属性值。

将登录控件转换为模板时可用的属性更少

图 7:登录控件转换为模板时可用的属性较少 (单击以查看全尺寸图像)

可以根据需要修改 中的 LayoutTemplate HTML 标记。 同样,可以随意向模板添加任何新的 Web 控件。 但是,登录控件的核心 Web 控件保留在模板中并保留其分配 ID 的值非常重要。 特别是,不要删除或重命名 UserNamePassword TextBox、 RememberMe CheckBox、 LoginButton 按钮、 FailureText 标签或 RequiredFieldValidator 控件。

若要收集访问者的电子邮件地址,我们需要将 TextBox 添加到模板。 在包含 Password TextBox 的表行 (<tr>) 和保存“下次 CheckBox 时记住我”的表行之间添加以下声明性标记:

<tr>
 <td align="right">
 <asp:Label ID="EmailLabel" runat="server" AssociatedControlID="Email">Email:</asp:Label>
 </td>
 <td>
 <asp:TextBox ID="Email" runat="server"></asp:TextBox>
 <asp:RequiredFieldValidator ID="EmailRequired" runat="server" 
 ControlToValidate="Email" ErrorMessage="Email is required." 
 ToolTip="Email is required." ValidationGroup="myLogin">*</asp:RequiredFieldValidator>
 </td>
</tr>

添加 Email TextBox 后,通过浏览器访问页面。 如图 8 所示,登录控件的用户界面现在包含第三个文本框。

登录控件现在包括用户Email地址的文本框

图 8:登录控件现在包含用户Email地址的文本框 (单击以查看全尺寸图像)

此时,Login 控件仍在使用 Membership.ValidateUser 方法来验证提供的凭据。 相应地,在 TextBox 中输入 Email 的值与用户是否可以登录没有关系。 在步骤 3 中,我们将了解如何重写 Login 控件的身份验证逻辑,以便仅当用户名和密码有效且提供的电子邮件地址与文件上的电子邮件地址匹配时,凭据才被视为有效。

步骤 3:修改登录控件的身份验证逻辑

当访问者提供其凭据并单击“登录”按钮时,将随之发出回发,登录控件将完成其身份验证工作流。 工作流首先引发 LoggingIn 事件。 与此事件关联的任何事件处理程序可以通过将 属性设置为 e.Canceltrue来取消登录操作。

如果未取消登录操作,则工作流将通过引发 Authenticate 事件进行。 如果事件有事件处理程序 Authenticate ,则它负责确定提供的凭据是否有效。 如果未指定事件处理程序,则 Login 控件使用 Membership.ValidateUser 方法来确定凭据的有效性。

如果提供的凭据有效,则会创建表单身份验证票证, LoggedIn 引发事件 ,并将用户重定向到相应的页面。 但是,如果凭据被视为无效,则会引发事件LoginError,并显示一条消息,通知用户其凭据无效。 默认情况下,在失败时,Login 控件只需将其 FailureText Label 控件的 Text 属性设置为失败消息, (登录尝试未成功。请) 重试。 但是,如果 Login 控件的 FailureAction 属性 设置为 RedirectToLoginPage,则 Login 控件会向登录页发出 , Response.Redirect 并追加查询字符串参数 loginfailure=1 (这会导致 Login 控件) 显示失败消息。

图 9 提供了身份验证工作流的流程图。

登录控件的身份验证工作流

图 9:登录控件的身份验证工作流 (单击以查看全尺寸图像)

注意

如果想知道何时使用 FailureAction的页面 RedirectToLogin 选项,请考虑以下方案。 现在,我们的 Site.master 母版页在匿名用户访问时,左侧列中会显示文本“Hello,陌生人”,但假设我们要将该文本替换为 Login 控件。 这将允许匿名用户从站点上的任何页面登录,而不是要求他们直接访问登录页面。 但是,如果用户无法通过母版页呈现的 Login 控件登录,则可能需要将他们重定向到登录页 (Login.aspx) ,因为该页面可能包含未添加到母版页的其他说明、链接和其他帮助(例如用于创建新帐户或检索丢失密码的链接)。

创建Authenticate事件处理程序

为了插入自定义身份验证逻辑,需要为 Login 控件的事件 Authenticate 创建事件处理程序。 为 Authenticate 事件创建事件处理程序将生成以下事件处理程序定义:

protected void myLogin_Authenticate(object sender, AuthenticateEventArgs e)
{
}

如你所看到的, Authenticate 事件处理程序将类型的 AuthenticateEventArgs 对象作为其第二个输入参数传递。 类 AuthenticateEventArgs 包含一个名为 Authenticated 的布尔值属性,该属性用于指定提供的凭据是否有效。 然后,我们的任务是在此处编写代码,以确定提供的凭据是否有效,并相应地设置 e.Authenticate 属性。

确定和验证提供的凭据

使用 Login 控件的 UserNamePassword 属性 来确定用户输入的用户名和密码凭据。 若要确定输入到任何其他 Web 控件 (的值(如 Email 我们在上一步) 中添加的 TextBox),请使用 LoginControlID.FindControl (“”controlID) 获取对模板 ID 中属性等于 controlID的 Web 控件的编程引用。 例如,若要获取对 TextBox 的 Email 引用,请使用以下代码:

TextBox EmailTextBox = myLogin.FindControl("Email") as TextBox;

为了验证用户的凭据,需要执行两项操作:

  1. 确保提供的用户名和密码有效
  2. 确保输入的电子邮件地址与尝试登录的用户的电子邮件地址匹配

若要完成第一个检查只需使用 方法,Membership.ValidateUser如步骤 1 中所示。 对于第二个检查,我们需要确定用户的电子邮件地址,以便我们可以将其与他们输入到 TextBox 控件中的电子邮件地址进行比较。 若要获取有关特定用户的信息,请使用 Membership 类的 GetUser 方法

方法 GetUser 具有多个重载。 如果在不传入任何参数的情况下使用,它将返回有关当前登录用户的信息。 若要获取有关特定用户的信息,请调用 GetUser 传入其用户名。 无论采用哪种方式, GetUser 都返回一个 MembershipUser 对象,该对象具有 、EmailIsOnlineIsApproved、 等属性UserName

以下代码实现这两个检查。 如果两者都通过,则 e.Authenticate 设置为 true,否则将分配 false它。

protected void myLogin_Authenticate(object sender, AuthenticateEventArgs e)
{
    // Get the email address entered
    TextBox EmailTextBox = myLogin.FindControl("Email") as TextBox;
    string email = EmailTextBox.Text.Trim();

    // Verify that the username/password pair is valid
    if (Membership.ValidateUser(myLogin.UserName, myLogin.Password))
    {
        // Username/password are valid, check email
        MembershipUser usrInfo = Membership.GetUser(myLogin.UserName);
        if (usrInfo != null && string.Compare(usrInfo.Email, email, true) == 0)
        {
            // Email matches, the credentials are valid
            e.Authenticated = true;
        }
        else
        {
            // Email address is invalid...
            e.Authenticated = false;
        }
    }
    else
    {
        // Username/password are not valid...
        e.Authenticated = false;
    }
}

完成此代码后,尝试以有效用户身份登录,输入正确的用户名、密码和电子邮件地址。 请重试,但这次故意使用不正确的电子邮件地址 (见图 10) 。 最后,使用不存在的用户名第三次尝试。 在第一种情况下,应成功登录到站点,但在最后两种情况下,应看到登录控件的凭据无效消息。

提供不正确的Email地址时,Tito 无法登录

图 10:提供不正确的Email地址时,Tito 无法登录 (单击以查看全尺寸图像)

注意

如步骤 1 中成员资格框架如何处理无效登录尝试部分所述,调用 方法并传递无效凭据时 Membership.ValidateUser ,它会跟踪无效的登录尝试,并在用户超过指定时间范围内无效尝试的特定阈值时将其锁定。 由于自定义身份验证逻辑调用 ValidateUser 方法,有效用户名的错误密码将增加无效的登录尝试计数器,但在用户名和密码有效但电子邮件地址不正确的情况下,此计数器不会递增。 这种行为很合适,因为黑客不太可能知道用户名和密码,但必须使用暴力破解技术来确定用户的电子邮件地址。

步骤 4:改进登录控件的无效凭据消息

当用户尝试使用无效凭据登录时,Login 控件会显示一条消息,说明登录尝试失败。 具体而言, 控件显示其 FailureText 属性指定的消息,该属性的默认值为“你的登录尝试未成功”。 请重试。

回想一下,用户凭据可能无效的原因有很多:

  • 用户名可能不存在
  • 用户名存在,但密码无效
  • 用户名和密码有效,但用户尚未获得批准
  • 用户名和密码有效,但用户被锁定 (很可能是因为它们超出了指定时间范围内的无效登录尝试次数)

使用自定义身份验证逻辑时可能还有其他原因。 例如,使用我们在步骤 3 中编写的代码,用户名和密码可能有效,但电子邮件地址可能不正确。

无论凭据无效的原因是什么,Login 控件都显示相同的错误消息。 对于帐户尚未获得批准或已被锁定的用户来说,这种缺乏反馈可能会造成混淆。不过,通过一些工作,我们可以让 Login 控件显示更合适的消息。

每当用户尝试使用无效凭据登录时,Login 控件都会引发其 LoginError 事件。 继续并为此事件创建事件处理程序,并添加以下代码:

protected void myLogin_LoginError(object sender, EventArgs e)
{
    // Determine why the user could not login...
    myLogin.FailureText = "Your login attempt was not successful. Please try again.";

    // Does there exist a User account for this user?
    MembershipUser usrInfo = Membership.GetUser(myLogin.UserName);
    if (usrInfo != null)
    {
        // Is this user locked out?
        if (usrInfo.IsLockedOut)
        {
            myLogin.FailureText = "Your account has been locked out because of too many invalid login attempts. Please contact the administrator to have your account unlocked.";
        }
        else if (!usrInfo.IsApproved)
        {
            myLogin.FailureText = "Your account has not yet been approved. You cannot login until an administrator has approved your account.";
        }
    }
}

上述代码首先将 Login 控件的 FailureText 属性设置为默认值, (登录尝试未成功。请) 重试。 然后,它会检查提供的用户名是否映射到现有用户帐户。 如果是,它将查询生成的 MembershipUser 对象的 IsLockedOutIsApproved 属性,以确定帐户是否已被锁定或尚未获得批准。 在任一情况下,属性 FailureText 都会更新为相应的值。

若要测试此代码,请特意尝试以现有用户身份登录,但使用的密码不正确。 在 10 分钟内连续执行此操作五次,帐户将被锁定。如图 11 所示,即使使用正确的密码) ,后续登录尝试也始终会失败 (,但现在将显示更具描述性的“你的帐户已被锁定”,因为无效登录尝试过多。 请与管理员联系,获取帐户解锁消息。

Tito 执行的无效登录尝试次数过多,已被锁定

图 11:Tito 执行的无效登录尝试次数过多,并且已被锁定 (单击以查看全尺寸图像)

摘要

在本教程之前,我们的登录页根据用户名/密码对的硬编码列表验证了提供的凭据。 在本教程中,我们更新了页面,以针对成员资格框架验证凭据。 在步骤 1 中,我们了解了以编程方式使用 Membership.ValidateUser 方法。 在步骤 2 中,我们已将手动创建的用户界面和代码替换为 Login 控件。

Login 控件呈现标准登录用户界面,并针对成员资格框架自动验证用户的凭据。 此外,如果凭据有效,登录名控件通过表单身份验证将用户登录。 简而言之,只需将 Login 控件拖动到页面上即可获得功能齐全的登录用户体验,无需额外的声明性标记或代码。 而且,Login 控件高度可自定义,允许对呈现的用户界面和身份验证逻辑进行精细控制。

此时,访问我们网站的访问者可以创建新的用户帐户并登录到网站,但我们尚未考虑基于经过身份验证的用户限制对页面的访问。 目前,任何经过身份验证或匿名的用户都可以查看我们网站上的任何页面。 除了按用户控制对网站页面的访问之外,我们可能拥有某些功能取决于用户的页面。 下一教程介绍如何根据登录的用户限制访问和页面内功能。

编程愉快!

深入阅读

有关本教程中讨论的主题的详细信息,请参阅以下资源:

关于作者

Scott Mitchell 是多本 ASP/ASP.NET 书籍的作者,4GuysFromRolla.com 的创始人,自 1998 年以来一直从事 Microsoft Web 技术工作。 Scott 担任独立顾问、培训师和作家。 他的最新书是 山姆斯在24小时内 ASP.NET 2.0自学。 可在 上或通过他的博客http://ScottOnWriting.NET联系 mitchell@4guysfromrolla.com Scott。

特别感谢

本教程系列由许多有用的审阅者查看。 本教程的主要审阅者是 Teresa Murphy 和 Michael Olivero。 有兴趣查看我即将发布的 MSDN 文章? 如果是,请在 处放置一行 mitchell@4GuysFromRolla.com