如何:在您的ASP.NET应用中用C#实现基于表单的认证(Q301240)
- 微软ASP.NET (包括.NET框架)
- 微软Visual C# .NET (2002)
- 微软SQL Server 2000 (所有版本)
- 微软SQL Server 版本7.0
如果您需要查阅本文的Microsoft Visual Basic .NET版本,请参见
Q308157。
本文引用了下列微软.NET框架类库的命名空间:
- System.Data.SqlClient
- System.Web.Security
本文内容
- 概述
- 需求
- 使用Visual C# .NET建立一个ASP.NET应用
- 在web.config中修改安全性设置
- 建立一个数据库表来存贮用户详细信息
- 建立一个Logon.aspx文件
- 添加事件响应代码来验证用户
- 建立一个Default.aspx文件
- 附注
- 参考文献
本文描述了如何通过使用一个数据库存贮用户信息来实现基于表单的认证。
返回
下面所列的是推荐的软、硬件和网络环境:
- 微软Visual Studio .NET
- 微软Internet Information Server (IIS) 版本5.0以上
- 微软SQL Server
- 打开Visual Studio .NET。
- 单击文件菜单,选择新建项目。
- 建立一个新的ASP.NET网络应用,并指定位置和名字。
这一段描述了如何添加、修改
和
之间的信息来设置ASP.NET应用使用基于表单的用户认证。
- 在项目浏览器中,打开Web.config文件。
- 在 属性中改变认证模式为Forms:mode="Forms"
- 在
后插入
标签,并填入相应的属性。(要获得更多关于这些属性的信息,请参见MSDN文档,或者参见本文后面“参考文献”所列的快速入门文档。)拷贝下面的代码,并点击“编辑”菜单中的“作为HTML粘贴”选项,把这段代码粘贴到文件的
段中:
- 在
段中添上拒绝匿名访问的代码,如下所示:
本段主要介绍了如何建立一个简单的数据库来存储用户名、密码、和用户角色。您需要角色这一列来存储用户的角色信息,从而实现基于角色的安全体系。
- 在Windows“开始”菜单中,点击“运行”,并输入“notepad”来打开写字板。
- 选中下面的SQL脚本代码,右击这段代码,然后点击“拷贝”。在写字板中,点击“编辑”菜单中的“粘贴”选项来粘贴下面的代码:
if exists (select * from sysobjects where id = object_id(N'[dbo].[Users]') and OBJECTPROPERTY(id, N'IsUserTable') = 1) drop table [dbo].[Users] GO CREATE TABLE [dbo].[Users] ( [uname] [varchar] (15) NOT NULL , [Pwd] [varchar] (25) NOT NULL , [userRole] [varchar] (25) NOT NULL , ) ON [PRIMARY] GO ALTER TABLE [dbo].[Users] WITH NOCHECK ADD CONSTRAINT [PK_Users] PRIMARY KEY NONCLUSTERED ( [uname] ) ON [PRIMARY] GO INSERT INTO Users values('user1','user1','Manager') INSERT INTO Users values('user2','user2','Admin') INSERT INTO Users values('user3','user3','User') GO
- 将文件保存为User.sql。
- 用安装了微软SQL Server的机器,在Query Analyzer中打开刚刚建立的脚本User.sql。在工具栏的数据库列表中,选择数据库“pubs”,然后执行这个脚本。脚本中的这段代码建立了一个简单的用户表,并将数据库pubs中的表调整为在这个样例应用中能够使用的格式。
- 在项目中添加一个web表单,命名为Logon.aspx。
- 拷贝下面的代码,并点击“编辑”菜单中的“作为HTML粘贴”选项,把这段代码粘贴到文件的
本段介绍了登录界面对应的code-behind页面中的代码(Logon.aspx.cs)。
- 双击“Logon按钮”来打开Logon.aspx.cs文件。
- 在该文件中导入需要的命名空间:
using System.Data.SqlClient; using System.Web.Security;
- 建立一个ValidateUser函数通过在数据库中查找的方法来验证用户身份。(确保您改变了Connection string以使它指向您的数据库)
private bool ValidateUser(string uid, string passwd) { SqlConnection cnn; SqlCommand cmd; SqlDataReader dr; cnn = new SqlConnection("server=localhost;uid=sa;pwd=password;database=pubs"); cmd = new SqlCommand("Select *from users where uname='" + uid + "'",cnn); cnn.Open(); dr = cmd.ExecuteReader(); while (dr.Read()) { if (string.Compare(dr["Pwd"].ToString(),passwd,false)==0) { cnn.Close(); return true; } } cnn.Close(); return 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); else Response.Redirect("logon.aspx", true); }
- 生成认证令牌并对它进行加密,利用加密结果建立一个cookie,并将其添加到Response的cookies中,最后重定向页面。使用这个方法,您可以在如何创建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; Response.Cookies.Add(ck); string strRedirect; strRedirect = Request["ReturnUrl"]; if (strRedirect==null) strRedirect = "default.aspx"; Response.Redirect(strRedirect, true); } else Response.Redirect("logon.aspx", true); }
- 调用RedirectFromLoginPage方法来自动产生表单的认证cookie,并在cmdLogin_ServerClick事件中将用户重定向到适当的页面:
- 请确认以下代码已被添加到了由表单设计器自动产生的InitializeComponent函数中:
this.cmdLogin.ServerClick += new System.EventHandler(this.cmdLogin_ServerClick);
本节建立了一个测试页面,用户通过认证后将被重定向到这个页面。如果用户没有事先登录就试图访问本页面,则他们会被重定向到登录页面上。
- 重命名已经存在的WebForm1.aspx页面为Default.aspx,并在编辑器中打开。
- 切换到“HTML”视图,并把下面的代码拷贝到标签中间:
- 切换的“设计”视图,并保存页面。
- 在code-behind页面中导入需要的命名空间:
using System.Web.Security;
- 双击SignOut来打开code-behind页面(Default.aspx.cs),并拷贝下面的代码到cmdSignOut_ServerClick事件响应函数中:
private void cmdSignOut_ServerClick(object sender, System.EventArgs e) { FormsAuthentication.SignOut(); Response.Redirect("logon.aspx", true); }
- 请确保下面的代码被添加到了由表单设计器自动产生的InitializeComponent函数中:
this.cmdSignOut.ServerClick += new System.EventHandler(this.cmdSignOut_ServerClick);
- 保存并编译项目。您现在就可以只用这个应用了。
- 您可能会想要安全地在数据中存储密码。您可以使用FormsAuthentication类工具中的HashPasswordForStoringInConfigFile函数在您存储密码前对它进行加密。
- 您可能会想要将SQL连接信息存储到设置文件(Web.config)中,以便您能够容易地在需要的时候修改。
- 如果考虑添加一些代码来防止黑客使用不同的密码组合试图登录。则您可以在代码中限制登录次数(例如2-3次)。如果一个用户接连几次都没能登录成功,则还可以通过在数据库中设置一个标志位来阻止该用户登录,直到他通过别的页面或者打您的服务支持热线重新激活了该账号。另外,应该考虑在必要的时候适当增加错误处理函数。
- 由于用户人正是基于认证cookie的,您可能想要在应用中使用Secure Sockets Layer (SSL),从而没有人能够欺骗认证cookie。
- 基于表单的认证需要您在客户端启用并允许使用cookie。
- 设置的timeout参数控制了认证cookie产生的时间间隔,您可以选择一个参数值,以获得良好的性能和安全性。
- 互联网上的一些中间代理和缓存可能会缓存包含cookie设置头部的Web服务器响应,接着这些响应返回给不同的用户。因为基于表单的认证通过cookie来认证用户,引起的后果是,用户可以从中间代理或缓存获得本应返回给其他用户的cookie,无意(或有意)的模仿其他用户。下面的文章解释了如何解决这个问题。
Q263730 Site Server Users May Be Authenticated Under the Wrong Account