明輝手游網(wǎng)中心:是一個(gè)免費(fèi)提供流行視頻軟件教程、在線學(xué)習(xí)分享的學(xué)習(xí)平臺(tái)!

ASP.NET中的HTTP模塊與處理程序

[摘要]介紹   在Internet時(shí)代的開端,客戶端的需求非常有限;.htm文件就可以滿足他們的需求。但是,隨著時(shí)間的流逝,客戶端需求的擴(kuò)充超越了.htm文件或靜態(tài)文件所包含的功能。  開發(fā)者需要擴(kuò)充或擴(kuò)展Web服務(wù)器的功能。Web服務(wù)器廠商設(shè)計(jì)了不同的解決方案,但是都遵循同一個(gè)主題“向Web服務(wù)器插入...

  介紹

  在Internet時(shí)代的開端,客戶端的需求非常有限;.htm文件就可以滿足他們的需求。但是,隨著時(shí)間的流逝,客戶端需求的擴(kuò)充超越了.htm文件或靜態(tài)文件所包含的功能。

  開發(fā)者需要擴(kuò)充或擴(kuò)展Web服務(wù)器的功能。Web服務(wù)器廠商設(shè)計(jì)了不同的解決方案,但是都遵循同一個(gè)主題“向Web服務(wù)器插入某些組件”。所有的Web服務(wù)器補(bǔ)充技術(shù)都允許開發(fā)者建立并插入組件以增強(qiáng)Web服務(wù)器的功能。微軟公司提出了ISAPI(Internet服務(wù)器API),網(wǎng)景公司提出了NSAPI(網(wǎng)景服務(wù)器API)等等。

  ISAPI是一種重要的技術(shù),它允許我們?cè)鰪?qiáng)與ISAPI兼容的Web服務(wù)器(IIS就是一種與ISAPI兼容的Web服務(wù)器)的能力。我們使用下面的組件達(dá)到這個(gè)目的:

  · ISAPI擴(kuò)展

  · ISAPI過濾器

  ISAPI擴(kuò)展是使用Win32動(dòng)態(tài)鏈接庫(kù)來實(shí)現(xiàn)的。你可以把ISAPI擴(kuò)展看作是一個(gè)普通的應(yīng)用程序。ISAPI擴(kuò)展的處理目標(biāo)是http請(qǐng)求。這意味著你必須調(diào)用它們才能激活它們。 你可以認(rèn)為ISAPI過濾器僅僅就是一個(gè)過濾器而已?蛻舳嗣看蜗蚍⻊(wù)器發(fā)出請(qǐng)求的時(shí)候,請(qǐng)求要經(jīng)過過濾器?蛻舳瞬恍枰谡(qǐng)求中指定過濾器,只需要簡(jiǎn)單地把請(qǐng)求發(fā)送給Web服務(wù)器,接著Web服務(wù)器把請(qǐng)求傳遞給相關(guān)的過濾器。接下來過濾器可能修改請(qǐng)求,執(zhí)行某些登錄操作等等。

  由于這些組件的復(fù)雜性,實(shí)現(xiàn)它們非常困難。開發(fā)者不得不使用C/C++來開發(fā)這些組件,但是對(duì)于很多人來說,使用C/C++進(jìn)行開發(fā)簡(jiǎn)直就是痛苦的代名詞。

  那么ASP.NET提供什么東西來實(shí)現(xiàn)這些功能呢?ASP.NET提供的是HttpHandler(HTTP處理程序)和HttpModule(HTTP模塊)。

  在深入了解這些組件的詳細(xì)信息之前,了解一下http請(qǐng)求經(jīng)過HTTP模塊和HTTP處理程序的時(shí)候的處理流程是有價(jià)值的。

  建立示例應(yīng)用程序

  我建立了下面一些的C#項(xiàng)目以演示應(yīng)用程序的不同組件:

  · NewHandler (HTTP處理程序)

  · Webapp (演示HTTP處理程序)

  · SecurityModules (HTTP模塊)

  · Webapp2 (演示HTTP模塊)

  這些應(yīng)用程序的安裝步驟:

  · 解開attached zip文件中的所以代碼。

  · 建立兩個(gè)虛擬目錄webapp和webapp2;把這兩個(gè)目錄指向Webapp和Webapp2應(yīng)用程序的實(shí)際物理目錄。

  · 把NewHandler項(xiàng)目中的Newhandler.dll文件復(fù)制到webapp應(yīng)用程序的bin目錄。

  · 把SecurityModules項(xiàng)目中的SecurityModules.dll文件復(fù)制到webapp2應(yīng)用程序的bin目錄中。
  ASP.NET請(qǐng)求的處理過程

  ASP.NET請(qǐng)求處理過程是基于管道模型的,在模型中ASP.NET把http請(qǐng)求傳遞給管道中的所有模塊。每個(gè)模塊都接收http請(qǐng)求并有完全控制權(quán)限。模塊可以用任何自認(rèn)為適合的方式來處理請(qǐng)求。一旦請(qǐng)求經(jīng)過了所有HTTP模塊,就最終被HTTP處理程序處理。HTTP處理程序?qū)φ?qǐng)求進(jìn)行一些處理,并且結(jié)果將再次經(jīng)過管道中的HTTP模塊:


  請(qǐng)注意在http請(qǐng)求的處理過程中,只能調(diào)用一個(gè)HTTP處理程序,然而可以調(diào)用多個(gè)HTTP模塊。

  Http處理程序

  HTTP處理程序是實(shí)現(xiàn)了System.Web.IHttpHandler接口的.NET組件。任何實(shí)現(xiàn)了IHttpHandler接口的類都可以用于處理輸入的HTTP請(qǐng)求。HTTP處理程序與ISAPI擴(kuò)展有些類似。HTTP處理程序和ISAPI擴(kuò)展的差別在于在URL中可以使用HTTP處理程序的文件名稱直接調(diào)用它們,與ISAPI擴(kuò)展類似。

  HTTP處理程序?qū)崿F(xiàn)了下列方法:

方法名稱描述
ProcessRequest這個(gè)方法實(shí)際上是http處理程序的核心。我們調(diào)用這個(gè)方法來處理http請(qǐng)求。
IsReusable我們調(diào)用這個(gè)屬性來決定http處理程序的實(shí)例是否可以用于處理相同其它類型的請(qǐng)求。HTTP處理程序可以返回true或false來表明它們是否可以重復(fù)使用。


  你可以使用web.config或者machine.config文件把這些類映射到http請(qǐng)求上。映射完成以后,當(dāng)接收到相應(yīng)請(qǐng)求的時(shí)候ASP.NET會(huì)實(shí)例化http處理程序。我們將解釋如何在web.config和/或machine.config文件中定義所有這些細(xì)節(jié)信息。

  ASP.NET還通過IHttpHandlerFactory接口支持http處理程序的擴(kuò)展。ASP.NET提供了把http請(qǐng)求路由到實(shí)現(xiàn)IHttpHandlerFactory接口的類的對(duì)象上的能力。此外,ASP.NET還利用了Factory設(shè)計(jì)模式。這種模式為建立一組相關(guān)對(duì)象而不提供具體類的功能提供了接口。簡(jiǎn)單的說,你可以把用于建立依賴傳遞進(jìn)來的參數(shù)建立的http處理程序?qū)ο蟮念惪醋魇莊actory(工廠)。我們不用指定需要實(shí)例化的特定的http處理程序;http處理程序工廠處理這種事務(wù)。這樣做的優(yōu)點(diǎn)在于如果未來實(shí)現(xiàn)IHttpHandler接口的對(duì)象的實(shí)現(xiàn)方法發(fā)生了改變,只要接口仍然相同,客戶端就不會(huì)受到影響。

  下面是IHttpHandlerFactory接口中的方法列表:

方法名稱描述
GetHandler這個(gè)方法負(fù)責(zé)建立適當(dāng)?shù)奶幚沓绦虿阉闹羔樂祷氐秸{(diào)用代碼(ASP.NET運(yùn)行時(shí))。這個(gè)方法返回的處理程序?qū)ο髴?yīng)該實(shí)現(xiàn)了IHttpHandler接口。
ReleaseHandler這個(gè)方法負(fù)責(zé)在請(qǐng)求處理完成后釋放http處理程序。Factory 實(shí)現(xiàn)決定了它的操作。Factory 實(shí)現(xiàn)可以是實(shí)際摧毀實(shí)例,也可以把它放入緩沖池供以后使用。


  在配置文件中注冊(cè)HTTP處理程序和HTTP處理程序工廠

  ASP.NET在下面的配置文件中維護(hù)自己的配置信息:

  · machine.config

  · web.config

  machine.config文件包含應(yīng)用于計(jì)算機(jī)上安裝的所有Web應(yīng)用程序的配置設(shè)置信息。

  web.config文件對(duì)于每個(gè)Web應(yīng)用程序來說是特定的。每個(gè)Web應(yīng)用程序都有自己的web.config文件。Web應(yīng)用程序的任何子目錄也可能包含自己的web.config文件;這使得它們能夠覆蓋父目錄的設(shè)置信息。
為了給我們的Web應(yīng)用程序添加HTTP處理程序,你可以使用<httpHandlers>和<add>節(jié)點(diǎn)。實(shí)際上,處理程序都帶有<add>節(jié)點(diǎn),列舉在<httpHandlers>和</httpHandlers>節(jié)點(diǎn)之間。下面是添加HTTP處理程序的一個(gè)普通的例子:

<httpHandlers>
。糰dd verb="supported http verbs" path="path" type="namespace.classname, assemblyname" />
<httpHandlers>


  在上面的XML中,

  · Verb屬性指定了處理程序支持的HTTP動(dòng)作。如果某個(gè)處理程序支持所有的HTTP動(dòng)作,請(qǐng)使用“*”,否則使用逗號(hào)分隔的列表列出支持的動(dòng)作。因此如果你的處理程序只支持HTTP GET和POST,那么verb屬性就應(yīng)該是“GET, POST”。

  · Path屬性指定了需要調(diào)用處理程序的路徑和文件名(可以包含通配符)。例如,如果你希望自己的處理程序只有在test.xyz文件被請(qǐng)求的時(shí)候才被調(diào)用,那么path屬性就包含“test.xyz”,如果你希望含有.xyz后綴的所有文件都調(diào)用處理程序,path屬性應(yīng)該包含“*.xyz”。

  · Type屬性用名字空間、類名稱和部件名稱的組合形式指定處理程序或處理程序工廠的實(shí)際類型。ASP.NET運(yùn)行時(shí)首先搜索應(yīng)用程序的bin目錄中的部件DLL,接著在全局部件緩沖(GAC)中搜索。

  ASP.NET運(yùn)行時(shí)對(duì)HTTP處理程序的使用方式

  無論你是否相信,ASP.NET都使用HTTP請(qǐng)求實(shí)現(xiàn)了大量的自己的功能。ASP.NET使用處理程序來處理.aspx、 .asmx、 .soap和其它ASP.NET文件。

  下面是machine.config文件中的一個(gè)片段:

<httpHandlers>
。糰dd verb="*" path="trace.axd" type="System.Web.Handlers.TraceHandler"/>
。糰dd verb="*" path="*.aspx" type="System.Web.UI.PageHandlerFactory"/>
 <add verb="*" path="*.ashx" type="System.Web.UI.SimpleHandlerFactory"/>
。糰dd verb="*" path="*.config" type="System.Web.HttpForbiddenHandler"/>
。糰dd verb="GET,HEAD" path="*" type="System.Web.StaticFileHandler"/>
 . . . . . .
 . . . . . .
</httpHandlers>


  在上面的配置信息中你可以看到對(duì).aspx文件的所有請(qǐng)求都由System.Web.UI.PageHandlerFactory類來處理。與此類似,對(duì).config文件和其它文件(它們不能被客戶端直接訪問)的所有請(qǐng)求都由System.Web.HttpForbiddenHandler類處理。你可能已經(jīng)猜到,當(dāng)訪問這些文件的時(shí)候,該類簡(jiǎn)單地給客戶端返回一個(gè)錯(cuò)誤信息。

  執(zhí)行HTTP處理程序

  現(xiàn)在你將看到如何實(shí)現(xiàn)一個(gè)HTTP處理程序。那么我們的新處理程序要做什么任務(wù)呢?前面我提到,處理程序大多數(shù)用于給Web服務(wù)器添加新功能;因此,我將建立一個(gè)處理程序來處理新的文件類型——擴(kuò)展名為.15seconds的文件。我們建立了這個(gè)處理程序并在我們的Web應(yīng)用程序的web.config文件中注冊(cè)之后,所有對(duì).15seconds文件的請(qǐng)求都將由這個(gè)新處理程序來處理。

  你可能正在考慮這個(gè)處理程序的使用方法。如果你希望引入一種新的服務(wù)器腳本語言或動(dòng)態(tài)服務(wù)器文件(例如asp、aspx)該怎么辦呢?你可以為它編寫一個(gè)自己的處理程序。類似地,如果你希望在IIS上運(yùn)行Java小程序、JSP和其它一些服務(wù)器端Java組件應(yīng)該怎么辦呢?一種方法是安裝某些ISAPI擴(kuò)展(例如Allaire或Macromedia Jrun)。你也可以編寫自己的HTTP處理程序。盡管這對(duì)于第三方廠商(例如Allaire和Macromedia)來說是很復(fù)雜的事務(wù),但是它卻是個(gè)很有吸引力的選擇,因?yàn)樗鼈兊腍TTP處理能夠能夠訪問ASP.NET運(yùn)行時(shí)暴露的所有新功能。

  實(shí)現(xiàn)我們的HTTP處理程序包含以下步驟:

  1.編寫一個(gè)實(shí)現(xiàn)IHttpHandler接口的類。

  2. 在web.config或machine.config文件中注冊(cè)這個(gè)處理程序。

  3.在Internet服務(wù)管理器中把文件擴(kuò)展(.15seconds)映射到ASP.NET ISAPI擴(kuò)展DLL(aspnet_isapi.dll)上。

  第一步

  在Visual Studio.NET中建立一個(gè)新的C#類庫(kù)項(xiàng)目,并把它命名為“MyHandler”。Visual Studio.NET將自動(dòng)地給項(xiàng)目添加一個(gè)叫做“Class1.cs”的類。把它改名為“NewHandler”;在代碼窗口中打開這個(gè)類,并把類的名稱和構(gòu)造函數(shù)的名稱改成“NewHandler”。

  下面是NewHandler類的代碼:

using System;
using System.Web;

namespace MyHandler
{
 public class NewHandler : IHttpHandler
 {
  public NewHandler()
  {
   // TODO: 此處添加構(gòu)造邏輯
  }

  #region Implementation of IHttpHandler
  public void ProcessRequest(System.Web.HttpContext context)
  {
   HttpResponse objResponse = context.Response ;
   objResponse.Write("<html><body><h1>Hello 15Seconds Reader ") ;
   objResponse.Write("</body></html>") ;
  }

  public bool IsReusable
  {
   get
   {
    return true;
   }
  }
  #endregion
 }
}


  你在ProcessRequest方法中可以看到,該HTTP處理程序通過System.Web.HttpContext對(duì)象訪問了所有作為參數(shù)傳遞給它的ASP.NET內(nèi)部對(duì)象。實(shí)現(xiàn)ProcessRequest方法只需要簡(jiǎn)單地從context對(duì)象中提取HttpResponse對(duì)象并把發(fā)送一些HTML給客戶端。類似地,IsReusable返回true,表明這個(gè)處理程序可以被重復(fù)用作處理其它的HTTP請(qǐng)求。

  我們編譯上面的代碼并把它放到webapp虛擬目錄的bin目錄之中。

  第二步

  在web.config文件中通過添加下面的文本來注冊(cè)這個(gè)處理程序:

<httpHandlers>
。糰dd verb="*" path="*.15seconds" type="MyHandler.NewHandler,MyHandler"/>
</httpHandlers>


  第三步

  由于我們已經(jīng)建立了用于處理新擴(kuò)展文件的處理程序了,我們還需要把這個(gè)擴(kuò)展名告訴IIS并把它映射到ASP.NET。如果你不執(zhí)行這個(gè)步驟而試圖訪問Hello.15seconds文件,IIS將簡(jiǎn)單地返回該文件而不是把它傳遞給ASP.NET運(yùn)行時(shí)。其結(jié)果是該HTTP處理程序不會(huì)被調(diào)用。

  運(yùn)行Internet服務(wù)管理器,右鍵點(diǎn)擊默認(rèn)Web站點(diǎn),選擇屬性,移動(dòng)到Home目錄選項(xiàng)頁(yè),并點(diǎn)擊配置按鈕。應(yīng)用程序配置對(duì)話框彈出來了。點(diǎn)擊添加按鈕并在可執(zhí)行字段輸入aspnet_isapi.dll文件路徑,在擴(kuò)展字段輸入.15seconds。其它字段不用處理;該對(duì)話框如下所示:


  點(diǎn)擊確認(rèn)按鈕關(guān)閉應(yīng)用程序配置和默認(rèn)Web站點(diǎn)屬性對(duì)話框。

  現(xiàn)在我們運(yùn)行Internet Explorer并輸入url:http://localhost/webapp/hello.15seconds,看到的頁(yè)面如下:

  HTTP處理程序中的對(duì)話狀態(tài)

  維護(hù)對(duì)話狀態(tài)是Web應(yīng)用程序執(zhí)行的最通常的事務(wù)。HTTP處理程序也需要訪問這些對(duì)話狀態(tài)。但是HTTP處理程序的默認(rèn)設(shè)置是沒有激活對(duì)話狀態(tài)的。為了讀取和/或?qū)懭霠顟B(tài)數(shù)據(jù),需要HTTP處理程序?qū)崿F(xiàn)下面的接口之一:

  · IRequiresSessionState

  · IReadOnlySessionState.

  當(dāng)HTTP處理程序需要讀寫對(duì)話數(shù)據(jù)的時(shí)候,它必須實(shí)現(xiàn)IRequiresSessionState接口。如果它只讀取對(duì)話數(shù)據(jù),實(shí)現(xiàn)IReadOnlySessionState接口就可以了。

  這兩個(gè)接口都是標(biāo)記接口,并沒有包含任何方法。因此,如果你希望激活NewHandler處理程序的對(duì)話狀態(tài),要像下面的代碼一樣聲明NewHandler類:

public class NewHandler : IHttpHandler, IRequiresSessionState


  HTTP模塊

  HTTP模塊是實(shí)現(xiàn)了System.Web.IhttpModule接口的.NET組件。這些組件通過在某些事件中注冊(cè)自身,把自己插入ASP.NET請(qǐng)求處理管道。當(dāng)這些事件發(fā)生的時(shí)候,ASP.NET調(diào)用對(duì)請(qǐng)求有興趣的HTTP模塊,這樣該模塊就能處理請(qǐng)求了。

  HTTP模塊實(shí)現(xiàn)了IhttpModule接口的下面一些方法:

方法名稱描述
Init這個(gè)方法允許HTTP模塊向HttpApplication 對(duì)象中的事件注冊(cè)自己的事件處理程序。
Dispose這個(gè)方法給予HTTP模塊在對(duì)象被垃圾收集之前執(zhí)行清理的機(jī)會(huì)。


  HTTP模塊可以向System.Web.HttpApplication對(duì)象暴露的下面一些方法注冊(cè):

事件名稱描述
AcquireRequestState當(dāng)ASP.NET運(yùn)行時(shí)準(zhǔn)備好接收當(dāng)前HTTP請(qǐng)求的對(duì)話狀態(tài)的時(shí)候引發(fā)這個(gè)事件。
AuthenticateRequest當(dāng)ASP.NET 運(yùn)行時(shí)準(zhǔn)備驗(yàn)證用戶身份的時(shí)候引發(fā)這個(gè)事件。
AuthorizeRequest當(dāng)ASP.NET運(yùn)行時(shí)準(zhǔn)備授權(quán)用戶訪問資源的時(shí)候引發(fā)這個(gè)事件。
BeginRequest當(dāng)ASP.NET運(yùn)行時(shí)接收到新的HTTP請(qǐng)求的時(shí)候引發(fā)這個(gè)事件。
Disposed當(dāng)ASP.NET完成HTTP請(qǐng)求的處理過程時(shí)引發(fā)這個(gè)事件。
EndRequest把響應(yīng)內(nèi)容發(fā)送到客戶端之前引發(fā)這個(gè)事件。
Error 在處理HTTP請(qǐng)求的過程中出現(xiàn)未處理異常的時(shí)候引發(fā)這個(gè)事件。
PostRequestHandlerExecute在HTTP處理程序結(jié)束執(zhí)行的時(shí)候引發(fā)這個(gè)事件。
PreRequestHandlerExecute在ASP.NET開始執(zhí)行HTTP請(qǐng)求的處理程序之前引發(fā)這個(gè)事件。在這個(gè)事件之后,ASP.NET 把該請(qǐng)求轉(zhuǎn)發(fā)給適當(dāng)?shù)腍TTP處理程序。
PreSendRequestContent在ASP.NET把響應(yīng)內(nèi)容發(fā)送到客戶端之前引發(fā)這個(gè)事件。這個(gè)事件允許我們?cè)趦?nèi)容到達(dá)客戶端之前改變響應(yīng)內(nèi)容。我們可以使用這個(gè)事件給頁(yè)面輸出添加用于所有頁(yè)面的內(nèi)容。例如通用菜單、頭信息或腳信息。
PreSendRequestHeaders 在ASP.NET把HTTP響應(yīng)頭信息發(fā)送給客戶端之前引發(fā)這個(gè)事件。在頭信息到達(dá)客戶端之前,這個(gè)事件允許我們改變它的內(nèi)容。我們可以使用這個(gè)事件在頭信息中添加cookie和自定義數(shù)據(jù)。
ReleaseRequestState當(dāng)ASP.NET結(jié)束所搜有的請(qǐng)求處理程序執(zhí)行的時(shí)候引發(fā)這個(gè)事件。
ResolveRequestCache我們引發(fā)這個(gè)事件來決定是否可以使用從輸出緩沖返回的內(nèi)容來結(jié)束請(qǐng)求。這依賴于Web應(yīng)用程序的輸出緩沖時(shí)怎樣設(shè)置的。
UpdateRequestCache當(dāng)ASP.NET完成了當(dāng)前的HTTP請(qǐng)求的處理,并且輸出內(nèi)容已經(jīng)準(zhǔn)備好添加給輸出緩沖的時(shí)候,引發(fā)這個(gè)事件。這依賴于Web應(yīng)用程序的輸出緩沖是如何設(shè)置的。


  除了這些事件之外,我們還可以使用四個(gè)事件。我們可以通過實(shí)現(xiàn)Web應(yīng)用程序的global.asax文件中一些方法來使用這些事件。

  這些事件是:

  · Application_OnStart

  當(dāng)?shù)谝粋(gè)請(qǐng)求到達(dá)Web應(yīng)用程序的時(shí)候引發(fā)這個(gè)事件。

  · Application_OnEnd

  準(zhǔn)備終止應(yīng)用程序之前引發(fā)這個(gè)事件。

  · Session_OnStart

  用戶對(duì)話的第一個(gè)請(qǐng)求引發(fā)這個(gè)事件。

  · Session_OnEnd

  放棄對(duì)話或者對(duì)話超期的時(shí)候引發(fā)這個(gè)事件。
  在配置文件中注冊(cè)HTTP模塊

  當(dāng)我們建立了HTTP模塊并把它復(fù)制到Web應(yīng)用程序的bin目錄或者全局部件緩沖(Global Assembly Cache)之后,接下來就應(yīng)該在web.config或machine.config中注冊(cè)它了。

  我們可以使用<httpModules>和<add>節(jié)點(diǎn)把HTTP模塊添加到Web應(yīng)用程序中。實(shí)際上模塊都使用<add>節(jié)點(diǎn)列舉在<httpModules>和</httpModules>節(jié)點(diǎn)之內(nèi)了。

  因?yàn)榕渲迷O(shè)置信息是可以繼承的,所以子目錄從父目錄那兒繼承配置設(shè)置信息。其結(jié)果是,子目錄可能繼承了一些不需要的HTTP模塊(它們是父配置信息的一部分);因此,我們需要一種刪除這些不需要的模塊的方法。我們可以使用<remove>節(jié)點(diǎn);如果我們希望刪除從應(yīng)用程序繼承得到的所有HTTP模塊,可以使用<clear>節(jié)點(diǎn)。

  下面的代碼是添加HTTP模塊的一個(gè)通用示例:

<httpModules>
<add type="classname, assemblyname" name="modulename" />
<httpModules>


  下面的代碼是從應(yīng)用程序中刪除HTTP模塊的一個(gè)通用示例:

<httpModules>
<remove name="modulename" />
<httpModules>


  在上面的XML中:

  · Type屬性用類和部件名稱的形式指定了HTTP模塊的實(shí)際類型。

  · Name屬性指定了模塊的友好名稱。其它應(yīng)用程序可以使用這個(gè)名稱來識(shí)別HTTP模塊。

  ASP.NET運(yùn)行時(shí)如何使用HTTP模塊

  ASP.NET運(yùn)行時(shí)使用HTTP模塊實(shí)現(xiàn)某些特殊的功能。下面的片段來自于machine.config文件,它顯示了ASP.NET運(yùn)行時(shí)安裝的HTTP模塊:

<httpModules>
。糰dd name="OutputCache" type="System.Web.Caching.OutputCacheModule"/>
。糰dd name="Session" type="System.Web.SessionState.SessionStateModule"/>
 <add name="WindowsAuthentication"
type="System.Web.Security.WindowsAuthenticationModule"/>
。糰dd name="FormsAuthentication"
type="System.Web.Security.FormsAuthenticationModule"/>
 <add name="PassportAuthentication"
type="System.Web.Security.PassportAuthenticationModule"/>
。糰dd name="UrlAuthorization"
type="System.Web.Security.UrlAuthorizationModule"/>
 <add name="FileAuthorization"
type="System.Web.Security.FileAuthorizationModule"/>
</httpModules>


  ASP.NET使用上面一些HTTP模塊來提供一些服務(wù),例如身份驗(yàn)證和授權(quán)、對(duì)話管理和輸出緩沖。由于這些模塊都注冊(cè)在machine.config文件中。

  實(shí)現(xiàn)一個(gè)提供安全服務(wù)的HTTP模塊

  現(xiàn)在我們實(shí)現(xiàn)一個(gè)HTTP模塊,它為我們的Web應(yīng)用程序提供安全服務(wù)。該HTTP模塊基本上是提供一種定制的身份認(rèn)證服務(wù)。它將接收HTTP請(qǐng)求中的身份憑證,并確定該憑證是否有效。如果有效,與用戶相關(guān)的角色是什么?通過User.Identity對(duì)象,它把這些角色與訪問我們的Web應(yīng)用程序頁(yè)面的用戶的標(biāo)識(shí)關(guān)聯(lián)起來。
下面是該HTTP模塊的代碼:

using System;
using System.Web;
using System.Security.Principal;

namespace SecurityModules
{
 /// Class1的總體描述。

 public class CustomAuthenticationModule : IHttpModule
 {
  public CustomAuthenticationModule()
  {
  }
  public void Init(HttpApplication r_objApplication)
  {
   // 向Application 對(duì)象注冊(cè)事件處理程序。
   r_objApplication.AuthenticateRequest +=
new EventHandler(this.AuthenticateRequest) ;
  }

  public void Dispose()
  {
   // 此處空出,因?yàn)槲覀儾恍枰鍪裁床僮鳌?br>  }

  private void AuthenticateRequest(object r_objSender,EventArgs r_objEventArgs)
  {
   // 鑒別用戶的憑證,并找出用戶角色。。
   1. HttpApplication objApp = (HttpApplication) r_objSender ;
   2. HttpContext objContext = (HttpContext) objApp.Context ;
   3. if ( (objApp.Request["userid"] == null)
   4.  (objApp.Request["password"] == null) )
   5.  {
   6.   objContext.Response.Write("<H1>Credentials not provided</H1>") ;
   7.   objContext.Response.End() ;
   8.  }

   9. string userid = " ;
   10. userid = objApp.Request["userid"].ToString() ;
   11. string password = " ;
   12. password = objApp.Request["password"].ToString() ;
 
   13. string[] strRoles ;
   14. strRoles = AuthenticateAndGetRoles(userid, password) ;
   15. if ((strRoles == null) (strRoles.GetLength(0) == 0))
   16. {
   17.  objContext.Response.Write("<H1>W(wǎng)e are sorry but we could not
find this user id and password in our database</H1>") ;
   18.  objApp.CompleteRequest() ;
   19. }

   20. GenericIdentity objIdentity = new GenericIdentity(userid,
"CustomAuthentication") ;
   21. objContext.User = new GenericPrincipal(objIdentity, strRoles) ;
  }

  private string[] AuthenticateAndGetRoles(string r_strUserID,string r_strPassword)
  {
   string[] strRoles = null ;
   if ((r_strUserID.Equals("Steve")) && (r_strPassword.Equals("15seconds")))
   {
    strRoles = new String[1] ;
    strRoles[0] = "Administrator" ;
   }
   else if ((r_strUserID.Equals("Mansoor")) && (r_strPassword.Equals("mas")))
   {
    strRoles = new string[1] ;
    strRoles[0] = "User" ;
   }
   return strRoles ;
  }
 }
}

  我們研究一下上面的代碼。

  我們是從Init函數(shù)開始的。這個(gè)函數(shù)把處理程序的AuthenticateRequest事件插入Application(應(yīng)用程序)對(duì)象的事件處理程序列表中。這將導(dǎo)致引發(fā)AuthenticationRequest事件的時(shí)候Application調(diào)用該方法。

  我們的HTTP模塊初始化之后,我們就可以調(diào)用它的AuthenticateRequest方法來鑒別客戶端請(qǐng)求。AuthenticateRequest方法是該安全/身份認(rèn)證機(jī)制的核心。在這個(gè)函數(shù)中:

  1和2行提取HttpApplication和HttpContext對(duì)象。3到7行檢測(cè)是否沒有給我們提供了用戶id或密碼。如果沒有提供,就顯示錯(cuò)誤信息,請(qǐng)求處理過程終止。

  9到12行從HttpRequest對(duì)象中提取用戶id和密碼。

  14行調(diào)用一個(gè)叫做AuthenticateAndGetRoles的輔助(helper)函數(shù)。這個(gè)函數(shù)主要執(zhí)行身份驗(yàn)證并決定用戶角色。上面的代碼采用了硬編碼(hard-coded),只允許兩個(gè)用戶使用,但是我們可以擴(kuò)展這個(gè)方法,并添加代碼與用戶數(shù)據(jù)庫(kù)交互操作并檢索用戶的角色。

  16到19行檢測(cè)是否有角色與用戶關(guān)聯(lián)。如果沒有就意味著傳遞給我們的憑證沒有通過驗(yàn)證;因此該憑證是無效的。因此,給客戶端發(fā)送一個(gè)錯(cuò)誤信息,并且請(qǐng)求結(jié)束了。

  20和21行非常重要,因?yàn)檫@兩行實(shí)際上告訴ASP.NET HTTP運(yùn)行時(shí)已登錄用戶的身份。這兩行成功執(zhí)行以后,我們的aspx頁(yè)面就能夠使用User對(duì)象訪問這些信息了。

  現(xiàn)在我們看一看這種身份驗(yàn)證機(jī)制的運(yùn)行情況。目前我們只允許下面兩個(gè)用戶登錄到系統(tǒng):

  · User id = Steve, Password = 15seconds, Role = Administrator
  · User id = Mansoor, Password = mas, Role = User

  注意用戶id和密碼是大小寫敏感的(區(qū)分大小寫)。

  首先試圖不提供憑證登錄系統(tǒng),在IE中輸入http://localhost/webapp2/index.aspx將看到下面的消息:


  現(xiàn)在試圖使用用戶id“Steve”和密碼“15seconds”登錄系統(tǒng)。輸入 http://localhost/webapp2/index.aspx?userid=Steve&password=15seconds你將看到下面的歡迎消息:


  現(xiàn)在試圖使用用戶id“Mansoor”和秘碼“mas”登錄系統(tǒng)。輸入http://localhost/webapp2/index.aspx?userid=Mansoor&password=mas你將看到下面的歡迎消息頁(yè)面:



  現(xiàn)在試圖使用錯(cuò)誤的用戶id和密碼組合來登錄系統(tǒng)。輸入http://localhost/webapp2/index.aspx?userid=Mansoor&password=xyz你將看到下面的錯(cuò)誤消息:


  這表明我們的安全模塊在起作用了。你可以通過在AuthenticateAndGetRoles方法中使用數(shù)據(jù)庫(kù)訪問代碼來擴(kuò)展該安全模塊。

  要使所有的部分都起作用,我們必須對(duì)web.config文件進(jìn)行一些修改。首先,由于我們要使用自己的身份驗(yàn)證,因此不需要其它的身份驗(yàn)證機(jī)制。為了達(dá)到這個(gè)目的,改變webapp2的web.config文件中的<authentication>節(jié)點(diǎn),如下所示:

<authentication mode="None"/>

  類似地,不允許匿名用戶訪問我們的Web站點(diǎn)。給web.config文件添加下面的語句:

<authorization>
 <deny users="?"/>
</authorization>

  用于至少能夠匿名訪問用于提供憑證的文件。在web.config文件中使用下面的配置設(shè)置信息把index.aspx作為唯一能夠匿名訪問的文件:

<location path="index.aspx">
。約ystem.web>
 。糰uthorization>
   <allow users="*"/>
 。/authorization>
。/system.web>
</location>

  結(jié)論

  你可能已經(jīng)意識(shí)到有了HTTP處理程序和模塊后,ASP.NET已經(jīng)給開發(fā)者提供了強(qiáng)大的能量。把你自己的組件插入ASP.NET請(qǐng)求處理管道,享受它的優(yōu)點(diǎn)吧。

  作為練習(xí),你應(yīng)該進(jìn)一步改進(jìn)程序,使示例身份驗(yàn)證模塊更加靈活,并能根據(jù)用戶的需要進(jìn)行調(diào)整。