ASP.NET中的HTTP模塊與處理程序
發(fā)表時(shí)間:2024-01-21 來源:明輝站整理相關(guān)軟件相關(guān)文章人氣:
[摘要]介紹 在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)整。