使用Forms身份验证
实际的Internet应用程序很少采用Windows和Passport身份验证方式。
如果要实现采集用户凭据并在内部进行处理,Forms身份验证是最理想的选择。为建立支持Forms身份验证的ASP.NET应用程序,需要这样设置web.config文件:
< system.web >
< authentication mode = " Forms " >
< forms loginUrl = " login.aspx " />
</ authentication >
< authenciation >
< deny users = " ? " />
</ authenciation >
</ system.web >
对于所有启用Forms身份验证和授权的文件夹中的资源,都能获得Forms身份验证机制的保护。应注意,只有那些由ASP.NET显式处理的资源类型才能受到保护。这些类型包括aspx、asmx、ashx文件,而不包括纯HTML页面和传统的ASP页面。但IIS 7.0允许我们更改这些设置--在Web服务器级的web.config文件中,将新的资源类型分配给ASP.NET标准的HTTP处理程序即可。
Forms身份验证控制流程
基于窗体的身份验证由实现FormsAuthenticationModule类的HTTP模块控制。当浏览器试图访问受保护的资源时,该模块会介入,并尝试查找请求者的身份验证票据。在ASP.NET 1.x中,票据不过是具有特定名称的cookie(该名称可配置)。在ASP.NET 2.0及更高版本中,它可以被配置成嵌入在URL中的值(无cookie Forms身份验证)。
如果没有找到有效票据,该模块会将当前请求重定向到某个登录页面。有关原页面的信息会设置在查询字符串中。用户在登录页面中提交凭据后,如果凭据被成功验证,用户代码再将浏览器重定向到原URL。附在登录页面查询字符串的原URL如下所示:
http://YourApp/login.aspx?ReturnUrl=original.aspx
对用户进行验证意味着需要颁发身份验证票据,并将其附在请求上。当浏览器再次请求该页面时,身份验证HTTP模块会收到这个票据,并据请求通过。
Forms身份验证带来一些固有的安全问题--所有数据都是页面明文方式传输。使用当今的浏览器技术,这种潜在的安全问题只能通过安全信道(HTTPS)来解决。
通过登录页面采集凭据
在登录页面需要两个文本框用来输入用户名与密码,另外还需要一个按钮用来执行登录操作。点击按钮后登录页面回发给服务器后,在服务器上应运行类似以下的代码:
void LogonUser( object sender, EventArgs e)
{
string user = userName.Text;
string pswd = passWord.Text;
// 验证登录用户名和密码
bool bAuthenticated = AuthenticateUser(user, pswd);
if (bAuthenticated)
// 登录成功,重定向到登录前页面
FormsAuthentication.RedirectFromLoginPage(user, false );
else
errorMsg.Text = " Sorry, yours seems not to be a valid account. " ;
}
RedirectFromLoginPage方法能够将已验证的用户重定向回最初始请求的URL,该方法有两个重载:
public static void RedirectFromLoginPage( string , bool );
public static void RedirectFromLoginPage( string , bool , string );
第一个参数为存储在身份验证票据中的用户名。第二个参数指示是否创建一个持久性的cookie来存储身份验证票据。如果为true,会用timeout特性指定的分钟数来设置该cookie的生存值,默认值为30分。这样,用户便会得到一个cookie,可以跨浏览器会话使用。如果为false,身份验证cookie只会在当前会话中有效。第三个参数是可选的,用于指定cookie的路径。
对用户进行身份验证
身份验证算法(即AuthenticateUser方法中的代码)完全取决于开发者。
注销
Forms身份验证模块提供了显式注销的方法--FormsAuthentication类的SignOUt方法。该方法能重置身份验证票据。如果使用cookie,SignOut方法会将HttpResponse的Cookie集合中的当前票据替换为空的、过期的cookie。
从ASP.NET 2.0版开始,FormsAuthentication类获得了一个新方法RedirectToLoginPage,该方法使用Response.Redirect可用于注销后返回到登录页面。
FormsAuthentication类
下表列出了FormsAuthentication类的属性,表中所有属性都是静态的:
在应用程序启动时,大多数属性的初始值会从web.config文件的<forms>配置区段读取。
FormsAuthentication类的方法
下表列出了FormsAuthentication类支持的方法,表中所有方法都是静态的:
Initialize方法用于读取配置文件的相关内容来对FormsAuthentication类的属性进行初始化,在应用程序的生存期内只调用一次。该方法还会为应用程序获取cookie值和加密密钥。
GetAuthCookie和SetAuthCookie方法分别用于获取和设置身份验证票据。如果应用程序以无cookie的方式进行Forms身份验证,这两个方法会对URL中的票据信息分别进行读和写操作。如果身份验证方法使用cookie,那么这两个方法则会针对cookie进行操作。
Forms身份验证的配置
Forms身份验证受<authentication>区段的<forms>子区段内容的控制,完整的语法如下:
< forms name = " cookie "
loginUrl = " url "
protection = " All|None|Encryption|Validation "
timeout = " 30 "
requireSSL = " true|false "
slidingExpiration = " true|false "
path = " / "
enableCrossAppsRedirects = " true|false "
cookieless = " UseCookies|UseUri|AutoDetect|UseDeviceProfile "
defaultUrl = " url "
domain = " string " >
</ forms >
下表对各属性做了简要说明:
基于cookie的Forms身份验证
在ASP.NET 1.x中,Forms身份验证主要基于cookie。身份验证票据的内容存储在cookie中,其名称取决于<forms>区段的name属性。该cookie中的信息能对发出请求的用户进行标识。
默认情况下,身份验证cookie有效期为30分钟,通过数据验证和加密进行保护。数据验证能够确保cookie的内容不会在沿途被篡改。加密使用的是AES加密算法,但我们可以将该算法改为DES或3DES。
若启用验证,创建该cookie时,会将一个验证密钥与cookie数据进行连接,计算一个机器身份验证码(MAC),并将其追加到传出的cookie中。该验证码来自web.config文件的<machineKey>区段。该区段还指定了加密密钥,在启用加密时使用。
无cookie的Forms身份验证
在ASP.NET 2.0和更高版本中,如果选用无cookie的身份验证,票据会嵌入URL,这种方式与使用无cookie会话时一样。
用于对用户进行身份验证的URL遵循这种模式:
http://YourApp/(F(XYZ....1234))/samples/default.aspx
票据经符合URL字符标准的方式进行编码后会被插入URL中,位于服务器名之后。
不论选择哪验证和加密方式,也不管身份验证模式是否使用cookie,存储在身份验证票据中的信息都会被编码。Forms身份验证会使用符合URI安全标准的Base64方式对其进行编码。编码后,每个字符占6位。
无cookie身份验证需要ISAPI筛选器来截获请求,抽取票据,并将其重写为正确的应用程序路径。该筛选器会将身份验证票据以请求标头的形式暴露。用于解析无cookie身份URL的组件与无cookie会话的解析组件相同,都是aspnet_filter.dll。为避免混淆,用于包装会话ID的分隔符为S(...),用于包装身份验证票据的分隔符为F(...)。
无cookie身份验证的选项
若要启用无cookie的身份验证,将配置文件<forms>区段的cookieless属性设为特定值即可。该属性可接受的值见下表:
UseDeviceProfile与AutoDetect间有细微的差别。如:假设用户通过IE 6.0发出请求,根据ASP.NET安装的浏览器功能数据库中的报告,该浏览器版本支持cookie。然而,某个用户可能关闭自己浏览器的cookie支持。AutoDetect能够正确处理这种禁用cookie的情况,而UseDeviceProfile在此种情况下仍会使用cookie,因此引发一个异常。
为与ASP.NET 1.x保持兼容,cookieless属性的默认值得为UseDeviceProfile。我们应将其改为AutoDetect比较合适。