IIS 和 ASP.NET 处理
注 本节内容适用于运行在 Windows 2000 上的 Internet 信息服务 (IIS) 5。
ASP.NET Web 应用程序和 Web 服务由在 ASP.NET 辅助进程 (aspnet_wp.exe) 的单一实例中执行的代码进行处理,即使是在多处理器计算机上,您仍然可以配置多个实例(每个处理器一个实例)。
IIS 对调用方进行身份验证并为其创建 Windows 访问令牌。如果在 IIS 内启用匿名访问,那么匿名Internet 用户帐户(一般为 IUSR_MACHINE)的 Windows 访问令牌由 IIS 创建。
对 ASP.NET 文件类型的请求由 ASP.NET ISAPI 扩展进行处理 (aspnet_isapi.dll),该扩展运行在 IIS (inetinfo.exe) 进程地址空间中。这将使用命名管道来与 ASP.NET 辅助进程通讯,如图 1 所示。IIS 将代表调用方的 Windows 访问令牌传递给ASP.NET 辅助进程。 ASP.NET Windows 身份验证模块用此来构造 WindowsPrincipal 对象,ASP.NET File 身份验证模块使用它来执行 Windows 访问检查,以确保调用方经身份验证可以访问请求的文件。

图 1. IIS 和 ASP.NET 通讯
注 访问令牌与进程有关。因此,在 inetinfo.exe 内运行的 ASP.NET ISAPI DLL 调用 DuplicateHandle,将令牌句柄复制到 aspnet_wp.exe 进程地址空间中,然后通过命名管道传递该句柄值。
应用程序隔离
辅助进程中单独的应用程序域(每个 IIS 虚拟目录一个,或每个 ASP.NET Web 应用程序或 Web 服务一个)用于提供隔离。
这与传统的 ASP 相反,在传统的 ASP 中,应用程序保护级别在 IIS 元数据库内进行配置,以确定 ASP 应用程序应当在带有 IIS (inetinfo.exe) 的进程中、在专用 Dllhost.exe实例中的进程之外还是在共享的(池)Dllhost.exe 实例中执行。
重要事项 在 IIS 内设置进程隔离级别对处理 ASP.NET Web 应用程序的方式没有影响。
ASP.NET ISAPI 扩展
ASP.NET ISAPI 扩展 (aspnet_isapi.dll) 运行在 IIS 进程地址空间 (inetinfo.exe) 中,并将ASP.NET 文件类型的请求通过命名管道转发至 ASP.NET 辅助进程。
通过 IIS 元数据库中定义的映射,将指定的 ASP.NET 文件类型映射到 ASP.NET ISAPI 扩展。在安装.NET 框架时建立标准 ASP.NET 文件类型(包括 .aspx, .asmx, .rem, .soap)的映射。
应用程序映射的查看步骤
1. | 从 AdministrativeTools 程序组启动 Internet 信息服务。 |
2. | 鼠标右键单击 Web 服务器计算机上的默认 Web 站点,然后单击 Properties。 |
3. | 单击 HomeDirectory 选项卡,然后单击 Configuration。 屏幕显示映射列表。您可查看映射到 Aspnet_isapi.dll 的文件类型。 |
IIS 6.0 和 Windows .NET 服务器
Windows .NET 服务器上的 IIS 6.0 会对当前进程排列做出重要更改。
• | 您将能够配置多个应用程序池,每个池可由一个或多个进程实例 (w3wp.exe) 提供服务。这将提供额外的容错和管理功能,并允许您隔离单独进程中的单独应用程序。 |
• | 将 ASP.NET 与 IIS 6.0 Kernel 模式 HTTP 侦听器集成,可将请求直接从操作系统传递至 ASP.NET 辅助进程。 |
更多信息
有关 IIS6 的详细信息,请参阅 TechNet 上的文章“IIS 6 概述” (http://www.microsoft.com/technet/treeview/default.asp?url=/TechNet/prodtechnol/iis/evaluate/iis6ovw.asp)。
ASP.NET 管道处理
使用 HTTP 模块对象来实现 ASP.NET 身份验证和授权机制,这是作为标准 ASP.NET 管道处理的一部积分进行调用的。图 2 所示为单个 Web 请求和响应通过对象管道传递。

图 2. ASP.NET 管道处理
ASP.NET 管道模型包括一个 HttpApplication 对象、多种 HTTP 模块对象以及一个 HTTP 句柄对象,还有它们相关的工厂对象(图 2 将其省略以求画面清晰)。在处理序列开始时使用 HttpRuntime 对象,在请求的整个生命周期内使用 HttpContext 对象以传达有关请求和响应的详细信息。
下表说明了由与 HTTP 处理管道相关联的对象执行的职责及操作:
• | HttpRuntime 对象检查从 IIS 接收的请求,并将它分配至 HttpApplication 对象的适当实例以进行处理。Aspnet_wp.exe 的每个应用程序域中都有一个 HttpApplication 对象池。在应用程序域、HttpApplication 对象和 IIS 虚拟目录之间存在着一一映射。即,ASP.NET 将单独的 IIS 虚拟目录视为单独的应用程序。 注 每个 Web 应用程序域中都有一个 HttpRuntime 实例。 |
• | HttpApplication 对象控制管道处理。创建单个 HttpApplication 对象来处理每个同时发出的 HTTP 请求。HttpApplication 对象由于性能原因汇集入池。 |
• | HTTP 模块对象是在 HTTP 请求和响应消息通过管道时对其进行处理的筛选器。它们可查看或更改请求和响应消息的内容。HTTP 模块是实现 IHttpModule 的类。 |
• | HTTP 句柄对象是 HTTP 请求的终结点,并为指定文类型提供请求处理。例如,一个句柄为 *.aspx 文件处理请求的同时,另一个句柄为 *.asmx 文件处理请求。HTTP 句柄生成并返回 HTTP 响应消息。HTTP 句柄是实现 IHttpHandler 的类。 |
• | HttpContext 对象用于整个管道以代表当前的 Web 请求和响应。它适用于管道中的所有模块和管道末端的句柄对象。HttpContext 对象公开多种属性,包括 User 属性,该属性包含代表调用方的 IPrincipal 对象。 |
Web 请求剖析
ASP.NET ISAPI 库 (Aspnet_isapi.dll) 运行在 IIS 进程地址空间 (Inetinfo.exe) 内。它将请求分配至 ASP.NET 辅助进程 (Aspnet_wp.exe) 中的 HttpRuntime 对象。为响应每个由 ASP.NET 接收的 Web 请求,出现以下操作集:
• | HttpRuntime 对象检查请求并将其转发到 HttpApplication 对象实例。 每个应用程序域(对象被汇集)至少有一个 HttpApplication 对象实例,每个 IIS 虚拟目录至少有一个应用程序域。特定虚拟目录中的初始文件请求会创建新的应用程序域和新的 HttpApplication 对象。 |
• | 从 Machine.config (它们包含在 <HttpModules> 元素中)读取 HTTP 模块列表。可将附加的自定义 HTTP 模块添加至指定应用程序的 Web.config。以下代码片断显示了 Machine.config 内的默认 <HttpModules> 元素。 <httpModules> <add name="OutputCache" type="System.Web.Caching.OutputCacheModule"/> <add name="Session" type="System.Web.SessionState.SessionStateModule"/> <add name="WindowsAuthentication" type="System.Web.Security.WindowsAuthenticationModule"/> <add name="FormsAuthentication" type="System.Web.Security.FormsAuthenticationModule"/> <add name="PassportAuthentication" type="System.Web.Security.PassportAuthenticationModule"/> <add name="UrlAuthorization" type="System.Web.Security.UrlAuthorizationModule"/> <add name="FileAuthorization" type="System.Web.Security.FileAuthorizationModule"/> </httpModules> 身份验证模块挂钩 AuthenticateRequest 事件,而授权模块挂钩 AuthorizeRequest 事件。 请求通过管道中的每个模块,尽管只加载了单个身份验证模块。这取决于 Web.config 中 <authentication> 元素的配置。例如,加载跟随 WindowsAuthenticationModule 中结果的 <authentication> 元素。 <authentication mode="Windows" /> |
• | 激活的身份验证模块负责创建 IPrincipal 对象并将其存储在 HttpContext.User 属性中。这非常重要,因为下游的授权模块使用这个 IPrincipal 对象来进行授权决定。 在没有身份验证的情况下(例如,在 IIS 内启用匿名访问,并且 ASP.NET 配置为 ),会有特殊的非配置模块将默认的匿名用户放入 HttpContext. User 属性中。因此,身份验证后的 HttpContext.User 始终非空。 如果实施自定义身份验证模块,则自定义模块中的代码必须创建 IPrincipal 对象并将其存储在 HttpContext.User 中。 注 ASP.NET 也根据 HttpContext.User 在 AuthenticateRequest 事件后限制 Thread.CurrentPrincipal。 |
• | HttpApplication 引发 AuthenticateRequest 事件(可在 global.asax 中挂钩该事件)。这允许您插入自定义处理代码,例如,加载与当前用户关联的角色集。但是,注意 WindowsAuthenticationModule 可自动完成该操作。角色列表从成员为经身份验证的 Windows 用户的 Windows 组集中获取。 |
• | 适当的身份验证模块完成它的处理后,如果请求未被终止,则调用授权模块。 |
• | 调用 UrlAuthorizationModule 时,它会检查 Machine.config 和 Web.config 中的 <authorization> 选项卡。如果有,它将从 HttpContext.User 中检索 IPrincipal 对象,并使用指定的谓词(GET、POST 等)检查是否授权用户访问请求的资源。 如果没有为用户授权,则 UrlAuthorizationModule 调用 HttpApplication.CompleteRequest,终止正常的消息处理。 UrlAuthorizationModule 返回 HTTP 401 状态代码。 |
• | 其次,将调用FileAuthorizationModule。它检查 HttpContext.User.Identity 中的 IIdentity 对象是否是 WindowsIdentity 类的实例。 如果 IIdentity 对象不是 WindowsIdentity,则 FileAuthorizationModule 不再执行进一步的处理。 如果具有 WindowsIdentity,则 FileAuthorizationModule 调用 AccessCheck API(通过 P/Invoke)来查看经身份验证的调用方(其访问令牌已由 IIS 传递至 ASP.NET,并由 WindowsIdentity 对象公开)是否被授权访问请求的文件。如果文件的安全描述符在其 DACL 中包含至少一个 Read ACE,则允许请求继续。否则,FileAuthorizationModule 调用 HttpApplication.CompleteRequest 并返回 401 状态代码。 |
Forms 身份验证处理
当以下元素位于 Web.config 中时,FormsAuthenticationModule 被激活。
<authentication mode="Forms" />
记住,对于 Forms 身份验证,在 Global.asax 内执行 Application_Authenticate 事件。对于 Forms 身份验证,会出现以下序列::
• | 在此代码内,可构造 IPrincipal 对象并将其存储在 HttpContext.User 中。这通常包括从自定义数据存储区(通常为 SQL Server 数据库或 Active Directory)检索出的角色列表。IPrincipal 对象通常是 GenericPrincipal 类的实例,但也可以是自定义 IPrincipal 类。 FormsAuthenticationModule 检查是否已创建 IPrincipal 对象。如果已创建,则由下游的授权模块来使用它。 如果没有创建,则 FormsAuthenticationModule 构造一个 GenericPrincipal(没有角色)并将其存储在上下文中。 如果没有角色信息,任何请求角色成员的授权检查(例如 PrincipalPermssion 请求)都将失败。 |
• | UrlAuthorizationModule 处理 AuthorizeRequest 事件。它的授权决定基于 HttpContext.User 内的 IPrincipal 对象。 |
Windows 身份验证处理
当以下元素位于 Web.config 内时, WindowsAuthenticationModule 被激活。
<authentication mode="Windows" />
对于 Windows 身份验证,会出现以下序列:
1. | WindowsAuthenticationModule 使用由 IIS 传递至 ASP.NET 的 Windows 访问令牌创建 WindowsPrincipal 对象。 |
2. | 它使用 P/Invoke 来调用 Win32 函数以获取用户所属的 Windows 组列表。这些用于填充 WindowsPrincipal 角色列表。 |
3. | 它将 WindowsPrincipal 对象存储在 HttpContext.User 中,以备下游的授权模块使用。 |
事件处理
HttpApplication 对象引发表 1 中所示的事件集。单个 HTTP 模块可挂钩这些事件(通过提供它们自身的事件句柄)。
表 1:由 HttpApplication 对象引发的事件 | |
事件 | 说明 |
BeginRequest | 请求处理启动前引发 |
AuthenticateRequest | 对调用方进行身份验证 |
AuthorizeRequest | 执行访问检查 |
ResolveRequestCache | 从缓存获取响应 |
AcquireRequestState | 加载会话状态 |
PreRequestHandlerExecute | 将请求发送至句柄对象前立即引发 |
PostRequestHandlerExecute | 将请求发送至句柄对象后立即引发 |
ReleaseRequestState | 存储会话状态 |
UpdateRequestCache | 更新响应缓存 |
EndRequest | 处理结束后引发 |
PreSendRequestHeaders | 发送经缓冲处理的响应头前引发 |
PreSendRequestContent | 发送经缓冲处理的响应体前引发 |
注 HTTP 句柄在 PreRequestHandlerExecute 和PostRequestHandlerExecute 事件之间执行。
最后两个事件具有不确定性,可在任何时间出现(例如,作为 Response.Flush 的结果)。其他所有事件均按顺序出现。
无需只为了挂钩其中一个事件而执行 HTTP 模块。也可向 Global.asax 添加事件句柄。除表 1 所列的事件(都可由单个 HTTP 模块对象挂钩)外,HttpApplication 对象还可引发 ASP 开发人员所熟悉的 Application_OnStart 和 Application_OnEnd 句柄。仅能够在 Global.asax 内处理这些事件。最后,也可为由单个 HTTP 模块对象引发的事件在 Global.asax 内执行自定义事件句柄。例如,会话状态模块引发 Session_OnStart 和 Session_OnEnd 事件。
执行自定义 HTTP 模块
要创建自己的 HTTP 模块并将其插入 ASP.NET 处理管道,请遵循以下步骤
1. | 创建实现 IHttpModule 的类。 |
2. | 将包含模块的程序集放入应用程序的 /bin 子目录下,或将其安装到全局程序集缓存中。 |
3. | 将 <HttpModules> 元素添加到应用程序的 web.config,如下所示。 <system.web> <httpModules> <add name="modulename" type="namespace. classname, assemblyname" /> </httpModules> </system.web> |
执行自定义 HTTP 句柄
您可能需要执行自定义 HTTP 句柄,例如,使用 .data 文件扩展名进行文件处理。
执行自定义 HTTP 句柄的步骤
1. | 向 IIS 元数据库添加映射以将 .data 文件扩展名映射到 ASP.NET ISAPI 扩展 (Aspnet_isapi.dll)。 在 IIS MMC 管理单元中用鼠标右键单击应用程序的虚拟目录,再单击 Configuration 按钮,然后单击 Add在 C:/Winnt/Microsoft.NET/Framework/v1.0.3705/aspnet_isapi.dll 下为 .data 文件创建新映射。 注 如果在添加映射时选择 Check that file exists 复选框,则文件必须实际存在。除非已经虚拟化没有映射到物理文件的路径,否则这通常是必需的要求。虚拟化路径以由 .NET Remoting 使用的 .rem 或 .soap 结尾。 |
2. | 创建一个实现 IHttpHandler 的类(如果您想异步处理请求,可选择创建 IHttpAsyncHandler)。 |
3. | 将包含句柄的程序集放入应用程序的 /bin 子目录,或可将其安装到全局程序集缓存中。 |
4. | 通过向应用程序的 Web.config 文件添加 <httpHandlers> 节来向处理管道添加句柄。 <system.web> <httpHandlers> <add verb="*" path="*.data" type="namespace.classname, assemblyname" /> </httpHandlers> </system.web> |