本文演示如何通过使用数据库来存储用户来实现基于表单的身份验证。 它指的是以下 Microsoft .NET Framework类库命名空间:

  • System.Data.SqlClient
  • System.Web.Security
  • 原始产品版本: ASP.NET
    原始 KB 编号: 301240

    以下列表概述了所需的推荐硬件、软件、网络基础结构和服务包:

  • Visual Studio .NET
  • Internet Information Services (IIS) 版本 5.0 或更高版本
  • SQL Server
  • 使用 C# .NET 创建 ASP.NET 应用程序

  • 打开 Visual Studio .NET。
  • 创建新的 ASP.NET Web 应用程序,并指定名称和位置。
  • 在Web.config文件中配置安全设置

    本部分演示如何添加和修改 <authentication> <authorization> 配置部分,以将 ASP.NET 应用程序配置为使用基于表单的身份验证。

  • 在“解决方案资源管理器”中打开 Web.config 文件。

  • 将身份验证模式更改为 窗体

  • 插入标记 <Forms> 并填充相应的属性。 复制以下代码,然后在 “编辑 ”菜单上选择“ 粘贴为 HTML ”以粘贴文件部分中的 <authentication> 代码:

    <authentication mode="Forms">
        <forms name=".ASPXFORMSDEMO" loginUrl="logon.aspx"
            protection="All" path="/" timeout="30" />
    </authentication>
    
  • 拒绝访问本部分中的匿名用户, <authorization> 如下所示:

    <authorization>
        <deny users ="?" />
        <allow users = "*" />
    </authorization>
    

    创建示例数据库表以存储用户详细信息

    本部分介绍如何创建示例数据库来存储用户的用户名、密码和角色。 如果要在数据库中存储用户角色并实现基于角色的安全性,则需要角色列。

  • “开始” 菜单上,选择 “运行”,然后键入记事本打开记事本。

  • 突出显示以下 SQL 脚本代码,右键单击代码,然后选择 “复制”。 在记事本中,选择“编辑”菜单上的“粘贴”以粘贴以下代码:

    if exists (select * from sysobjects where id =
    object_id(N'[dbo].[Users]') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
        drop table [dbo].[Users]
    CREATE TABLE [dbo].[Users] ([uname] [varchar] (15) NOT NULL,
        [Pwd] [varchar] (25) NOT NULL,
        [userRole] [varchar] (25) NOT NULL,
    ) ON [PRIMARY]
    ALTER TABLE [dbo].[Users] WITH NOCHECK ADD
        CONSTRAINT [PK_Users] PRIMARY KEY NONCLUSTERED
        ([uname]
        ) ON [PRIMARY]
    INSERT INTO Users values('user1','user1','Manager')
    INSERT INTO Users values('user2','user2','Admin')
    INSERT INTO Users values('user3','user3','User')
    
  • 将文件另存为 Users.sql

  • 在SQL Server计算机上,在查询分析器中打开 Users.sql。 从数据库列表中,选择 pubs 并运行脚本。 此操作创建一个示例用户表,并在 Pubs 数据库中填充要与此示例应用程序一起使用的表。

    创建 Logon.aspx 页面

  • 将新的 Web 窗体添加到名为 Logon.aspx 的项目。

  • 在编辑器中打开 Logon.aspx 页面,并切换到 HTML 视图。

  • 复制以下代码,并在“编辑”菜单上使用“粘贴为 HTML”选项在标记之间<form>插入代码:

    <font face="Verdana">Logon Page</font> <table> <td>Email:</td> <td><input id="txtUserName" type="text" runat="server"></td> <td><ASP:RequiredFieldValidator ControlToValidate="txtUserName" Display="Static" ErrorMessage="*" runat="server" ID="vUserName" /></td> <td>Password:</td> <td><input id="txtUserPass" type="password" runat="server"></td> <td><ASP:RequiredFieldValidator ControlToValidate="txtUserPass" Display="Static" ErrorMessage="*" runat="server" ID="vUserPass" /> <td>Persistent Cookie:</td> <td><ASP:CheckBox id="chkPersistCookie" runat="server" autopostback="false" /></td> <td></td> </table> <input type="submit" Value="Logon" runat="server" ID="cmdLogin"><p></p> <asp:Label id="lblMsg" ForeColor="red" Font-Name="Verdana" Font-Size="10" runat="server" />

    此 Web 窗体用于向用户显示登录表单,以便用户可以提供登录到应用程序的用户名和密码。

  • 切换到“设计”视图并保存页面。

    对事件处理程序进行编码,以便验证用户凭据

    本部分介绍放置在代码隐藏页 (Logon.aspx.cs) 中的代码。

  • 双击 “登录 ”以打开 Logon.aspx.cs 文件。

  • 在代码隐藏文件中导入所需的命名空间:

    using System.Data.SqlClient;
    using System.Web.Security;
    
  • 创建一个 ValidateUser 函数,通过查看数据库来验证用户凭据。 请确保更改 Connection 字符串以指向数据库。

    private bool ValidateUser( string userName, string passWord )
        SqlConnection conn;
        SqlCommand cmd;
        string lookupPassword = null;
        // Check for invalid userName.
        // userName must not be null and must be between 1 and 15 characters.
        if ( ( null == userName ) || ( 0 == userName.Length ) || ( userName.Length > 15 ))
            System.Diagnostics.Trace.WriteLine( "[ValidateUser] Input validation of userName failed." );
            return false;
        // Check for invalid passWord.
        // passWord must not be null and must be between 1 and 25 characters.
        if ( ( null == passWord ) || ( 0 == passWord.Length ) || ( passWord.Length > 25 ))
            System.Diagnostics.Trace.WriteLine( "[ValidateUser] Input validation of passWord failed." );
            return false;
            // Consult with your SQL Server administrator for an appropriate connection
            // string to use to connect to your local SQL Server.
            conn = new SqlConnection( "server=localhost;Integrated Security=SSPI;database=pubs" );
            conn.Open();
            // Create SqlCommand to select pwd field from users table given supplied userName.
            cmd = new SqlCommand( "Select pwd from users where uname=@userName", conn );
            cmd.Parameters.Add( "@userName", SqlDbType.VarChar, 25 );
            cmd.Parameters["@userName"].Value = userName;
            // Execute command and fetch pwd field into lookupPassword string.
            lookupPassword = (string) cmd.ExecuteScalar();
            // Cleanup command and connection objects.
            cmd.Dispose();
            conn.Dispose();
        catch ( Exception ex )
            // Add error handling here for debugging.
            // This error message should not be sent back to the caller.
            System.Diagnostics.Trace.WriteLine( "[ValidateUser] Exception " + ex.Message );
        // If no password found, return false.
        if ( null == lookupPassword )
            // You could write failed login attempts here to event log for additional security.
            return false;
        // Compare lookupPassword and input passWord, using a case-sensitive comparison.
        return ( 0 == string.Compare( lookupPassword, passWord, false ));
    
  • 可以使用两种方法之一生成表单身份验证 Cookie,并将用户重定向到事件中的相应页面 cmdLogin_ServerClick 。 为这两种方案提供了示例代码。 根据你的要求使用其中一个。

  • 调用该 RedirectFromLoginPage 方法以自动生成表单身份验证 Cookie,并在事件中将用户重定向到相应的页面 cmdLogin_ServerClick

    private void cmdLogin_ServerClick(object sender, System.EventArgs e)
        if (ValidateUser(txtUserName.Value,txtUserPass.Value))
            FormsAuthentication.RedirectFromLoginPage(txtUserName.Value, chkPersistCookie.Checked);
            Response.Redirect("logon.aspx", true);
    
  • 生成身份验证票证,对其进行加密,创建 Cookie,将其添加到响应,然后重定向用户。 此操作使你能够更好地控制如何创建 Cookie。 还可以包括自定义数据以及 FormsAuthenticationTicket 本例中的自定义数据。

    private void cmdLogin_ServerClick(object sender, System.EventArgs e)
        if (ValidateUser(txtUserName.Value,txtUserPass.Value))
            FormsAuthenticationTicket tkt;
            string cookiestr;
            HttpCookie ck;
            tkt = new FormsAuthenticationTicket(1, txtUserName.Value, DateTime.Now,
            DateTime.Now.AddMinutes(30), chkPersistCookie.Checked, "your custom data");
            cookiestr = FormsAuthentication.Encrypt(tkt);
            ck = new HttpCookie(FormsAuthentication.FormsCookieName, cookiestr);
            if (chkPersistCookie.Checked)
                ck.Expires=tkt.Expiration;
            ck.Path = FormsAuthentication.FormsCookiePath;
            Response.Cookies.Add(ck);
            string strRedirect;
            strRedirect = Request["ReturnUrl"];
            if (strRedirect==null)
                strRedirect = "default.aspx";
            Response.Redirect(strRedirect, true);
            Response.Redirect("logon.aspx", true);
    

    本部分将创建一个测试页面,用户在进行身份验证后会重定向到该页面。 如果用户浏览到此页面而未首先登录到应用程序,则会重定向到登录页。

  • 将现有 WebForm1.aspx 页重命名为 Default.aspx,并在编辑器中打开它。

  • 切换到 HTML 视图,并在标记之间 <form> 复制以下代码:

    <input type="submit" Value="SignOut" runat="server" id="cmdSignOut">
    

    此按钮用于从窗体身份验证会话注销。

  • 切换到“设计”视图并保存页面。

  • 在代码隐藏文件中导入所需的命名空间:

    using System.Web.Security;
    
  • 双击 SignOut 打开 Default.aspx.cs) (代码隐藏页,并在事件处理程序中 cmdSignOut_ServerClick 复制以下代码:

    private void cmdSignOut_ServerClick(object sender, System.EventArgs e)
        FormsAuthentication.SignOut();
        Response.Redirect("logon.aspx", true);
    
  • 请确保将以下代码添加到 InitializeComponent Web 窗体设计器生成的代码中的方法:

    this.cmdSignOut.ServerClick += new System.EventHandler(this.cmdSignOut_ServerClick);
    
  • 保存并编译项目。 现在可以使用该应用程序。

  • 你可能希望将密码安全地存储在数据库中。 在将密码存储在数据库或配置文件中之前,可以使用 FormsAuthentication 命名 HashPasswordForStoringInConfigFile 的类实用工具函数来加密密码。

  • 可能需要将 SQL 连接信息存储在配置文件 (Web.config) ,以便在必要时轻松修改它。

  • 可以考虑添加代码以防止尝试使用不同密码组合的黑客登录。 例如,可以包含仅接受两到三次登录尝试的逻辑。 如果用户无法在某些尝试中登录,你可能希望在数据库中设置一个标志,以不允许他们登录,直到用户通过访问其他页面或调用支持行重新启用其帐户。 此外,应在必要时添加适当的错误处理。

  • 由于用户是根据身份验证 Cookie 进行标识的,因此你可能希望在此应用程序上使用安全套接字层 (SSL) ,以便没有人能够欺骗正在传输的身份验证 Cookie 和任何其他有价值的信息。

  • 基于窗体的身份验证要求客户端在其浏览器上接受或启用 Cookie。

  • 配置部分的 <authentication> 超时参数控制重新生成身份验证 Cookie 的时间间隔。 可以选择提供更好性能和安全性的值。

  • Internet 上的某些中间代理和缓存可能会缓存包含 Set-Cookie 标头的 Web 服务器响应,然后返回给其他用户。 由于基于窗体的身份验证使用 Cookie 对用户进行身份验证,因此,此行为可能导致用户意外地 (或有意) 通过从中间代理或缓存接收一个最初不适合他们的 Cookie 来模拟其他用户。

  • 使用 XML 用户文件进行表单身份验证

  • ASP.NET Web 应用程序安全性

  • System.Web.Security 命名空间

  • ASP.NET 配置

  • ASP.NET 配置部分

  •