在程序中使用表单验证基本上需要完成以下步骤:
- 在 web.config 文件中配置表单验证
- 配置 IIS 允许匿名访问虚拟目录,同时配置 ASP.NET 来限制匿名用户访问 Web 程序
- 创建自定义的登录页面收集并验证用户名和密码,并和表单验证架构交互来生成票据
cookie 通过一个机器特定的密钥来加密,这个密钥在 machine.config 中定义。通常这个密钥的内容并不重要,但是在一个 Web 集群中,你需要保证所有的服务器使用同样的密钥,这样一台服务器才可以解密另一台服务器创建的 cookie。
1. 配置表单验证
必须在 web.config 文件中正确的配置表单验证。每一个 web.config 文件都有一个 <authentication> 配置节,将其 mode 特性设为 Forms 即可:
<authentication mode="Forms">
<!-- Detailed configuration options -->
</authentication>
<authentication> 配置节在程序的 web.config 文件中必须位于最高级别。如果 mode 特性被设为 Forms,ASP.NET 会加载并激活 FormsAuthenticationModule,它将为你完成大部分工作。上面的配置使用表单验证的默认配置,你可以通过在 machine.config 中的 <system.web> 节中添加设置覆盖这些默认设置。
你也可以通过在 <authentication> 的子标签 <forms> 中指定额外的设置来在程序中覆盖这些默认设置:
<authentication mode="Forms">
<forms
name="MyCookieName"
loginUrl="DbLogin.aspx"
timeout="20"
slidingExpiration="true"
cookieless="AutoDetect"
protection="All"
requireSSL="false"
enableCrossAppRedirects="false"
defaultUrl="MyDefault.aspx"
domain="www.mydomain.com"
path="/" />
</authentication>
这里,domain 属性被设置为一个代表你的域名的值。不过,在开发时通常会使用 URL http://localhost:<port>,此时,用于访问应用程序的 URL 和真实的域名并不相同,因此,表单验证将不可行。因为它把用于访问 WEB 服务器的 URL 和域名 cookie 的名称相匹配。
下表列出了大多数情况下会用到的属性:
选 项 |
默认值 |
描 述 |
name | .ASPXAUTH | 验证所使用的 HTTP cookie 的名字。多个应用程序应设置不同名字 |
loginUrl | login.aspx | 设置将用户跳转到哪一个页面完成登录 |
timeout | 30 | cookie 过期时间。如果经常过期,用户将不得不多次登录,程序可用性下降。如果从不过期,将面临 cookie被盗窃滥用的危险 |
slidingExpiration | true | 激活或禁止验证 cookie 的可变过期时间。如果激活它,意味着每次请求都会使 cookie 的过期时间复位 |
cookieless | UseDeviceProfile | 指定运行时是否用 cookie 将表单验证票据发送到客户端。可能的选项有 AutoDetect、UseCookies、UseUri、UseDeviceProfile |
protection | All | 指定 cookie 的保护级别。All 将对所有 cookie 加密并签名。可选的有 None、Encryption(仅加密)、Validation(仅签名) |
requireSSL | false | 如果设为true,在web服务器没有激活SSL时,浏览器不会发送 cookie,表单验证将不起作用 |
enableCrossAppRedirects | false | 激活跨应用程序重定向。这只有两个应用程序都依赖同一个凭证存储并使用相同的用户和角色集合时才起作用 |
defaultUrl | default.aspx | 如果用户登录成功,它包含了原来请求页面的 URL 信息 |
domain | <empty string> | 指定 cookie 在哪个域中有效。 |
path | / | 应用程序所处理的 cookie 的路径。推荐使用默认值。 |
web.config 中的凭证存储
你可以选择将用户凭证存放在什么地方,一个自定义文件或者数据库中或任何地方,只要你提供代码利用你的凭证存储验证用户输入的用户名和密码。
最简单的存储就是将用户凭证直接存储在 web.config 文件中,使用 <forms> 的子标签 <credentials> 中:
<authentication mode="Forms">
<forms
name="MyCookieName"
loginUrl="DbLogin.aspx"
timeout="20">
<credentials passwordFormat="Clear">
<user name="Admin" password="(Admin1)"/>
<user name="skysoot" password="111111"/>
</credentials>
</forms>
</authentication>
首先,使用 web.config 作为凭证存储只适用于很少用户的简单解决方案。在较大的场景中,应使用成员资格 API。其次,你可以散列化存储在 web.config 文件中的凭证和密码。散列化是对密码实施单向加密,这意味着密码将不能再被解密。
2. 禁止匿名用户访问
为了演示表单验证的重定向功能,现在开始,将使用拒绝所有非验证用户访问的简单技术。为此,配置 web.config,设置 <authorization> 元素添加一个新的授权规则,如下:
<authorization>
<deny users="?"/>
</authorization>
问号?是一个通配符,它代表所有的匿名用户。这样你拒绝了所有的匿名用户访问。每一个用户都必须被验证,每一次用户请求都需要表单验证票据(cookie)。
不像<authentication>元素,<authorization>元素并没有被限制在 Web 应用程序根目录下面的 web.config 文件中。你可以在任何子目录中使用它,这样你就可以为不同组的页面设置不同的授权规则了。
3. 创建自定义登录页面
现在,创建一个简单的自定义登录页面,此外,还必须拥有验证凭证的代码。如下图:
注意,浏览器地址中的 URL 包含了原来请求的页面并将其作为一个查询参数。这个参数在后面会被 FormsAuthentication 类用来重定向到原来请求的页面:
登录界面的页面代码如下:
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="DbLogin.aspx.cs" Inherits="DbLogin" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<div style="text-align:left">
Please Log into the System<br />
<asp:Panel ID="MainPanel" runat="server" Width="380px" BorderColor="Silver" BorderStyle="Solid"
BorderWidth="1px">
<br />
<table width="100%" border="0" cellpadding="0" cellspacing="0">
<tr>
<td width="30%" style="height: 43px">
User Name:
</td>
<td width="70%" style="height: 43px">
<asp:TextBox ID="UsernameText" runat="server" Width="80%" />
<asp:RequiredFieldValidator ID="UsernameRequiredValidator" runat="server" ErrorMessage="*"
ControlToValidate="UsernameText" />
<br />
<asp:RegularExpressionValidator ID="UsernameValidator" runat="server" ControlToValidate="UsernameText"
ErrorMessage="Invalid username" ValidationExpression="[\w| ]*" />
</td>
</tr>
<tr>
<td width="30%" style="height: 26px">
Password:
</td>
<td width="70%" style="height: 26px">
<asp:TextBox ID="PasswordText" runat="server" Width="80%" TextMode="Password" />
<asp:RequiredFieldValidator ID="PwdRequiredValidator" runat="server" ErrorMessage="*"
ControlToValidate="PasswordText" />
<br />
<asp:RegularExpressionValidator ID="PwdValidator" runat="server" ControlToValidate="PasswordText"
ErrorMessage="Invalid password" ValidationExpression='[\w| !"§$%&/()=\-?\*]*' />
</td>
</tr>
</table>
<br />
<asp:Button ID="LoginAction" runat="server" OnClick="LoginAction_Click" Text="Login" /><br />
<asp:Label ID="LegendStatus" runat="server" EnableViewState="false" Text="" /></asp:Panel>
</div>
</form>
</body>
</html>
可以看到,我们加入了验证控件,这点特别重要。绝不要相信用户的输入,它们可以保证用户只能输入有效的值。这里略微解释下正则表达式的含义:
- ValidationExpression="[\w| ]*":\w 相当于 [a-z;A-Z;0-9;_](数字、字母、下划线),空格则表示允许用户名中出现空格。
- ValidationExpression='[\w| !"§$%&/()=\-?\*]*':此处双引号作为可选的特殊字符,所以使用单引号来闭合特性值。此外,因为特性被包含在标签代码(HTML)中,所以 & 表明字符“&”可以出现在密码中。
在页面的后台代码中,我们应该编写验证用户凭证的代码。这里使用了 web.config 的凭证存储,所以验证代码非常简单:
protected void LoginAction_Click(object sender, EventArgs e)