简介
本文的第二部分主要是介绍如何使用ASP.NET实现我们自己的表格认证的方法。在第一部分中,我们讨论了表格认证的基本概念和原理。在阅读本文的第二部分之前,读者需要了解表格认证的一些基本概念,或者已经阅读过第一部分。
使用的页面:Default.aspx、Login.aspx、Web.config、Users.xml、HashPassword.aspx
在这个自定义表格认证的例子中,我们将自始至终地使用一个XML文档存储用户名和口令。建立该自定义表格认证所需要的一些准备工作:
Web.config文件中包含了Web应用程序的所有可配置的设置选项。我加亮显示了需要认真研究的代码:
<configuration> <system.web> <customErrors mode="Off"/> <authentication mode="Forms"> <forms name="AuthCookie" path="/" loginUrl="login.aspx" protection="All" timeout="10"> </forms> </authentication> <authorization> <deny users="?" /> </authorization> </system.web> 这部分加亮显示 <location path="unsecure"> <system.web> <authorization> <allow users="*"/> </authorization> </system.web> </location> 这部分加亮显示 </configuration> |
这个例子增加了一个名字为location的配置小节,它允许我们覆盖Web.config文件中system.web配置小节的设置。在本例中,我们希望允许匿名或没有通过认证的用户访问unsecure目录,常见的例子是整个Web应用都是安全的,只有注册页是个例外。通过允许匿名用户访问一个目录,我们可以将能够被任何人浏览的文件存储到该目录中。如果有必要,我们可以创建多个location小节。
在这个文件中,我们存储了所有认证需要的数据,例如用户名和口令。口令采用了SHA1算法进行加密,稍后我们会对SHA1算法进行解释。
<?xml version="1.0"?> <users> <jeff>A94A8FE5CCB19BA61C4C0873D391E987982FBBD3</jeff> <mike>A94A8FE5CCB19BA61C4C0873D391E987982FBBD3</mike> </users> |
在该文件中,有一个被称作users的小节,其中包含有每个用户的个人节点,在节点的开始、结束标志之间,有一个经过哈希处理的口令。很明显的是,该文件中也可以包含更多的信息,例如姓、名以及电话号码等。
该文件包含对一个用户进行认证所需要的全部逻辑。在本例中,我们将使用一个XML文件对用户进行认证,当然了我们也可以将本页的逻辑用于使用一个数据库对用户进行认证。
<%@Page Language="VB" %> <%@Import Namespace="System.Web.Security" %> <%@Import Namespace="System.Xml" %> <script language="VB" runat="server"> Sub ProcessLogin(objSender As Object, objArgs As EventArgs) Dim strCurrentPath As String = Request.PhysicalPath Dim strXMLDocPath As String = Left(strCurrentPath, InStrRev(strCurrentPath, "\")) & "users.xml" Dim strUser As String = txtUser.Text Dim strPassword As String = txtPassword.Text Dim strEncPassword As String = GetHashedPass(strPassword) Dim blnIsAuthenticated As Boolean Dim objXMLDoc As New XMLDocument() Try objXMLDoc.Load(strXMLDocPath) Catch objError As Exception ErrorMessage.innerHTML = "<b> The XML document could not be loaded.</b>.<br>" & _ objError.Message & "<br />" & objError.Source Exit Sub End Try Dim UserNodes As XmlNodeList UserNodes = objXMLDoc.GetElementsByTagName(strUser) 是否有用户名与输入的用户名相同的元素 If Not UserNodes Is Nothing Then Dim blnUserExists As Boolean = True Dim strUserCheck As String Try strUserCheck = UserNodes(0).FirstChild().Value Catch objError As Exception ErrorMessage.InnerHtml = "<b>Invalid username</b> please re-enter..." blnUserExists = False End Try If blnUserExists = True Then If strEncPassword = UserNodes(0).FirstChild().Value Then blnIsAuthenticated = True Else ErrorMessage.InnerHtml = "<b>Invalid password</b> please re-enter..." End If End if End If If blnIsAuthenticated Then FormsAuthentication.RedirectFromLoginPage(strUser, chkPersistLogin.Checked) End If End Sub Function GetHashedPass(ByVal aPassword As String) As String Return FormsAuthentication.HashPasswordForStoringInConfigFile(aPassword,"sha1") End Function </script> <html> <head> <title>Custom Forms Authentication Login Form</title> </head> <body bgcolor="#FFFFFF" text="#000000"> <form runat="server"> <table width="400" border="0" cellspacing="0" cellpadding="0"> <tr> <td width="80">Username : </td> <td width="10"> </td> <td><asp:TextBox Id="txtUser" runat="server"/></td> </tr> <tr> <td>Password : </td> <td width="10"> </td> <td><asp:TextBox Id="txtPassword" TextMode="Password" runat="server"/></td> </tr> <tr> <tr> <td></td> <td width="10"> </td> <td><asp:CheckBox id="chkPersistLogin" runat="server" />Remember my credentials <br> </td> </tr> <tr> <td> </td> <td width="10"> </td> <td><asp:Button Id="cmdLogin" OnClick="ProcessLogin" Text="Login" runat="server" /></td> </tr> </table> <br> <br> <div id="ErrorMessage" runat="server" /> </form> </body> </html> |
在本例中,我添加了对System.Web.Security和System.Xml的引用,因为我们将会用到这二个名字空间中的类。我们还编写了一个名字为ProcessLogin的过程,它的作用是检查表格数据(用户名和口令)与XML文件中所包含的口令和用户名是否相同。
首先,我们为文本编辑框创建了一些局部变量。由于需要得到users.xml文件的全路径,因此我们使用了
Request.PhysicalPath方法,然后对脚本文件名进行整理。另外我们还创建了一个变量,保存经过哈希处理后的口令。
其次,我们将XMLDoc.Load方法调用放在Try...Catch语句中。Try...Catch语句是ASP.NET中新增添的,它是处理错误和异常的一种很好的方式。在下面的代码,我们将用户节点表作为一个变量数组,使用getElementsByTagName方法将XML文件中的用户节点赋给它。然后检查该用户是否存在,如果存在,则检查用户输入的口令是否与存储在XML文件中的相同。如果用户存在,而且口令也相同,我们就将blnIsAuthenticated的值勤设置为true。在过程的末尾,如果blnIsAuthenticated的值为true,我们就调用RedirectFromLoginPage方法。当然了,我们也可以使用SetAuthCookie方法来完成同样的功能,但不会把用户引导到另一个网页。
在login.aspx文件的接口或HTML部分,我们有开发了2个服务器端正文框,1个服务器端复选框,1个按钮,在该按钮的onClick事件中,调用了ProcessLogin。我们还有一个在服务器端运行的div,它能够向用户显示出错信息。
该文件中的代码与本篇文章第一部分的default.aspx文件相同。
<%@Page Language="VB" %> <%@Import Namespace="System.Web.Security" %> <script language="vb" runat="server"> Sub SignOut(objSender As Object, objArgs As EventArgs) 删除用户认证的cookie并退出 FormsAuthentication.SignOut() 将用户引导到提交的网页 Response.Redirect(Request.UrlReferrer.ToString()) End Sub Sub Page_Load() 验证认证 If User.Identity.IsAuthenticated Then 显示认证信息 displayCredentials.InnerHtml = "Current User : <b>" & User.Identity.Name & _ "</b><br><br>Authentication Used : <b>" & _ User.Identity.AuthenticationType & "</b>" Else 显示错误信息 displayCredentials.InnerHtml = "Sorry, you have not been authenticated." cmdSignOut.disabled = True End If End Sub </script> <html> <head> <title>Forms Authentication</title> </head> <body bgcolor="#FFFFFF" text="#000000"> <span class="Header">Forms Based Authentication using Custom Method</span> <br> <br> <div id="displayCredentials" runat="server" /> <br> <br> <form runat="server"> <input id="cmdSignOut" type="submit" Value="Sign Out" runat="server" onserverclick="SignOut" /><p /> </form> </body> </html> |
该网页与本文第一部分中的default.aspx的功能完全相同,它只是简单地显示用户名和使用的认证方法。
这个网页允许一个未经认证的用户创建加密的口令,它可以用于在Web.config的credentials小节、XML文件或数据库中存储口令。
<clearcase/" target="_blank" >ccid_nobr><b>HashPassword.aspx代码</b></ccid_nobr> <%@Page Language="VB" %> <%@Import Namespace="System.Web.Security" %> <script language="VB" runat="server"> Sub GetHashedPass(objSender As Object, objArgs As EventArgs) Dim strEncPass As String strEncPass = FormsAuthentication.HashPasswordForStoringInConfigFile(txtPassword.Value,"sha1") hashedPass.InnerHtml = "Hashed Password for Web.config, XML File or Database<br><b>" & _ strEncPass & "</b>" End Sub </script> <html> <head> <title>Create Hashed Password</title> </head> <body bgcolor="#FFFFFF" text="#000000"> <b>Create Hashed Password</b> <form runat="server"> <table width="100%" border="0" cellspacing="0" cellpadding="0"> <tr> <td>Password to encrypt: <input id="txtPassword" type="password" runat="server" name="text"/> <input type="submit" value="Hash Pass" runat="server" onserverclick="GetHashedPass"/> </td> </tr> <tr> <tr> <td> </td> </tr> <tr> <td> <div id="hashedPass" runat="server"/> </td> </tr> </table> </form> </body> </html> |