如何透過IHttpHandler讓某虛擬目錄中檔案(例如Test.txt)必須登入才可瀏覽(或下載)

摘要:如何透過IHttpHandler讓某虛擬目錄中檔案(例如Test.txt)必須登入才可瀏覽

我們有時候會有這樣的需求,有些檔案也會希望使用者能夠經過登入驗證後,才能下載使用。然而對於.NET的驗證機制來說,他所保護的是aspx等asp.net的相關檔案,如果您的檔案是【txt文字檔】、【zip壓縮檔】、【doc Word檔】等,這些的檔案只要知道超連結,就可以直接下載。

那麼有沒有辦法讓這些的檔案也能夠跟aspx一樣,當瀏覽的時候,就檢查看是否有登入系統,如果未登入,就直接倒向到使用者登入畫面,當登入完成後,再進行該檔案的瀏覽或下載。

運作原理

我們知道在aspx的檔案在ASP.NET的驗證機制下,如果輸入ABC.aspx,系統會自動導向到我們指定的登入畫面(例如:Login.aspx),當登入驗證完成後,會再次導向回剛剛想要瀏覽的網頁ABC.aspx。而這些的機制,都是透過.NET Framework的ISAPI 【aspnet_isapi.dll】來處理的。因此我們希望我們指定的副檔名也能夠透過【aspnet_isapi.dll】的處理,做出相同的動作。因此要處理三件事情。

  • 撰寫IHttpHandler處理這些檔案類型
  • 設定Web.Config來註冊IHttpHandler,並且設定該資料夾Deny Users="?"
  • 在IIS中註冊這些副檔名由【aspnet_isapi.dll】處理(這樣才能啟動IHttpHandler)

撰寫處理過程

首先要在自己的系統上建立.NET的驗證機制。

接著,在自己的ASP.NET專案中建立一個資料夾(Files),希望未來存放在此資料夾中的指定檔案格式需要驗證。

再專案中新增一個類別(Class),命名為CFileSafe.vb,Imports命名空間System.Web
接著在Class中Implements IHttpHandler,VS自動會產生IsReusable的Property與ProcessRequest的Sub,接著撰寫處理Request的內容,判斷傳入的副檔名,依據不同的副檔名,指定不同的Response.ContentType,相關的程式內容如下:

Public Class CFileSafe
	Implements IHttpHandler

	Public ReadOnly Property IsReusable() As Boolean Implements System.Web.IHttpHandler.IsReusable
		Get

		End Get
	End Property

	Public Sub ProcessRequest(ByVal context As System.Web.HttpContext) Implements System.Web.IHttpHandler.ProcessRequest
		Dim FileName As String = context.Request.FilePath
		Dim tmpS() As String
		tmpS = FileName.Split(".")
		Dim FileExten As String = LCase(tmpS(UBound(tmpS)))
		Dim GetContentType As Boolean = False
		Select Case FileExten
			Case "txt"
				context.Response.ContentType = "text/plain"
				GetContentType = True
			Case "doc"
				context.Response.ContentType = "application/msword"
				GetContentType = True
			Case "xls"
				context.Response.ContentType = "application/ms-excel"
				GetContentType = True
			Case "ppt"
				context.Response.ContentType = "application/vnd.ms-powerpoint"
				GetContentType = True
			Case "pdf"
				context.Response.ContentType = "application/pdf"
				GetContentType = True
			Case "zip"
				context.Response.ContentType = "application/x-zip-compressed"
				GetContentType = True
			Case "gif"
				context.Response.ContentType = "image/gif"
				GetContentType = True

			Case "tif"
				context.Response.ContentType = "image/tiff"
				GetContentType = True

			Case "jpg"
				context.Response.ContentType = "image/jpeg"
				GetContentType = True

		End Select
		If GetContentType Then
			context.Response.TransmitFile(context.Request.FilePath)
			'context.Response.Write(FileExten) 
		Else
			'context.Response.Write(FileExten) 
			context.Response.Write("未設定檔案格式【" & FileExten & "】!!")
		End If

	End Sub
End Class

接著要針對此資料夾(Files)增加一個Web.config來註冊IHttpHandler,順便指定此資料夾不允許未登入使用者存取

<?xml version="1.0" encoding="utf-8"?> 
<configuration>
	<appSettings/>
	<connectionStrings/>
	<system.web>
		<httpHandlers>
			<add verb="*" path="*.*" type="CFileSafe"/>
		</httpHandlers>
		<authorization>
			<deny users="?"/>
		</authorization>
	</system.web>
</configuration>

程式的部分就到此為止,接著就可以放些測試的檔案到此資料夾中,並且拉出超連結到Login.aspx中,方便測試登入的驗證。

此時執行Login.aspx,點選超鏈結到Test.txt,卻發現還是沒有要求登入就直接顯示?原因是我們還少了最後的一個步驟→設定這些檔案格式給ISAPI處理

開啟IIS,瀏覽到我們ASP.NET應用程式中的Files資料夾,點選滑鼠右鍵→內容。
當我們要設定ISAPI的時候發現,由於他不是個應用程式,所以無法針對Files設定ISAPI

此時我們可以先暫時把該資料夾建立為應用程式,讓他可以設定,等設定完成後再把應用程式移除即可。

接著進入設定,來看看副檔名aspx的設定為何

將處理aspx的aspnet_isapi.dll路徑複製下來,等一下用相同的檔案來處理我們要處理的副檔名

接著新增一個副檔名的處理,我們舉txt來當作範例

接著把其他的副檔名用相同的方式設定,這個部份的畫面就省略了。

最後,Files其實不是個應用程式所以記得把應用程式移除

經過以上的設定後,再來測試看看就會發現,當瀏覽Files下的Test.txt的時候,系統會自動導向到Login.aspx要求登入,登入完成後,自動再導回Test.txt的內容進行瀏覽。接著測試zip也一樣,在未登入的狀況下,會要求使用者進行登入,登入完成後,就會出現下載儲存的對話方塊。


以下是簽名:


Microsoft MVP
Visual Studio and Development Technologies
(2005~2019/6) 
topcat
Blog:http://www.dotblogs.com.tw/topcat