以使用者為基礎的授權 (VB)

作者 :Scott Mitchell

注意

自本文撰寫以來,ASP.NET 成員資格提供者已被 ASP.NET 身分識別取代。 強烈建議您更新應用程式以使用 ASP.NET 身分識別 平臺,而不是本文撰寫時精選的成員資格提供者。 ASP.NET 身分識別對於 ASP.NET 成員資格系統有一些優點,包括 :

  • 更好的效能
  • 改善擴充性和可測試性
  • 支援 OAuth、OpenID Connect 和雙因素驗證
  • 宣告型身分識別支援
  • 與 ASP.Net Core 更好的互通性

下載程式代碼下載 PDF

在本教學課程中,我們將探討透過各種技術來限制頁面的存取和限制頁面層級功能。

簡介

大部分提供使用者帳戶的 Web 應用程式會這麼做,以限制特定訪客存取網站內的特定頁面。 例如,在大部分的線上消息板網站中,所有使用者 - 匿名和已驗證 - 都能夠檢視消息板的文章,但只有經過驗證的使用者可以流覽網頁來建立新的文章。 而且可能有一個系統管理頁面只能存取特定使用者 (或一組特定使用者) 。 此外,頁面層級功能可能會依使用者而有所不同。 檢視文章清單時,已驗證的使用者會顯示每個文章的評分介面,而此介面不適用於匿名訪客。

ASP.NET 可讓您輕鬆地定義使用者型授權規則。 只要在 中使用 Web.config 一些標記,就可以鎖定特定網頁或整個目錄,使其只能供指定的使用者子集存取。 頁面層級功能可以透過程式設計與宣告式方式,根據目前登入的使用者開啟或關閉。

在本教學課程中,我們將探討透過各種技術來限制頁面的存取和限制頁面層級功能。 現在就開始吧!

查看 URL 授權工作流程

表單驗證概 觀教學課程中所述,當 ASP.NET 執行時間處理 ASP.NET 資源的要求時,要求會在其生命週期期間引發一些事件。 HTTP 模組 是 Managed 類別,其程式碼會執行以回應要求生命週期中的特定事件。 ASP.NET 隨附數個 HTTP 模組,這些模組會在幕後執行基本工作。

其中一個這類 HTTP 模組是 FormsAuthenticationModule 。 如先前教學課程中所述,的主要功能 FormsAuthenticationModule 是判斷目前要求的身分識別。 這可藉由檢查位於 Cookie 或內嵌在 URL 中的表單驗證票證來完成。 此識別會在事件期間AuthenticateRequest發生。

另一個重要的 HTTP 模組是 UrlAuthorizationModule ,它會回應AuthorizeRequest 事件 (事件) 之後 AuthenticateRequest 發生。 會 UrlAuthorizationModule 檢查 中的 Web.config 組態標記,以判斷目前的身分識別是否具有流覽指定頁面的授權。 此程式稱為 URL 授權

我們將檢查步驟 1 中 URL 授權規則的語法,但首先讓我們看看 UrlAuthorizationModule ,根據要求是否獲得授權而定。 UrlAuthorizationModule如果 判斷要求已獲授權,則不會執行任何動作,而且要求會持續在其生命週期中。 不過,如果要求 未經 授權,則會 UrlAuthorizationModule 中止生命週期,並指示 Response 物件傳回 HTTP 401 未經授權 狀態。 使用表單驗證時,永遠不會將 HTTP 401 狀態傳回給用戶端,因為 如果 FormsAuthenticationModule 偵測到 HTTP 401 狀態,則會將其修改為 HTTP 302 重新 導向至登入頁面。

圖 1 說明 ASP.NET 管線、 FormsAuthenticationModule 未經授權要求送達時的 工作流程 UrlAuthorizationModule 。 特別是,圖 1 顯示 匿名訪客的要求 ProtectedPage.aspx ,這是拒絕匿名使用者存取的頁面。 由於訪客是匿名的,因此 會 UrlAuthorizationModule 中止要求並傳回 HTTP 401 未經授權狀態。 FormsAuthenticationModule接著,會將 401 狀態轉換成 302 重新導向至登入頁面。 透過登入頁面驗證使用者之後,系統會將他重新導向至 ProtectedPage.aspx 。 這次 會 FormsAuthenticationModule 根據使用者的驗證票證來識別使用者。 既然已驗證訪客,就會 UrlAuthorizationModule 允許存取頁面。

表單驗證和 URL 授權工作流程

圖 1:表單驗證和 URL 授權工作流程 (按一下以檢視完整大小的影像)

圖 1 描述匿名訪客嘗試存取匿名使用者無法使用的資源時所發生的互動。 在這種情況下,匿名訪客會重新導向至登入頁面,並嘗試造訪查詢字串中指定的頁面。 使用者成功登入之後,系統會自動將她重新導向回最初嘗試檢視的資源。

當匿名使用者提出未經授權的要求時,此工作流程相當簡單,而且很容易讓訪客瞭解發生什麼事和原因。 但請記住,即使已驗證的使用者提出要求,也會 FormsAuthenticationModule將任何 未經授權的使用者重新導向至登入頁面。 如果已驗證的使用者嘗試造訪缺少授權的頁面,這可能會導致令人困惑的使用者體驗。

假設網站已設定其 URL 授權規則,讓 ASP.NET 網頁 OnlyTito.aspx 只能存取 Tito。 現在,假設 Sam 造訪網站、登入,然後嘗試造訪 OnlyTito.aspxUrlAuthorizationModule將會停止要求生命週期,並傳回 HTTP 401 未經授權狀態,這會 FormsAuthenticationModule 偵測到 Sam,然後將 Sam 重新導向至登入頁面。 不過,由於 Sam 已經登入,她可能會想知道為什麼她已送回登入頁面。 她可能會因為登入認證遺失一些原因,或她輸入了不正確認證。 如果 Sam 從登入頁面重新輸入認證,她將會再次登入 () 並重新導向至 OnlyTito.aspxUrlAuthorizationModule會偵測到 Sam 無法造訪此頁面,而她將會返回登入頁面。

圖 2 描述這種令人困惑的工作流程。

預設工作流程可能會導致混淆的迴圈

圖 2:預設工作流程可能會導致混淆迴圈 (按一下即可檢視完整大小的影像)

圖 2 中說明的工作流程,即使最聰明的電腦造訪者,也可以快速運作。 我們將探討在步驟 2 中防止這種混淆迴圈的方式。

注意

ASP.NET 會使用兩種機制來判斷目前使用者是否可以存取特定的網頁:URL 授權和檔案授權。 檔案授權是由 實作, FileAuthorizationModule 它會藉由諮詢要求的檔案 (ACL) ACL 來判斷授權單位。 檔案授權最常與Windows 驗證搭配使用,因為 ACL 是適用于 Windows 帳戶的許可權。 使用表單驗證時,不論流覽網站的使用者為何,所有作業系統和檔案系統層級要求都會由相同的 Windows 帳戶執行。 由於本教學課程系列著重于表單驗證,因此我們不會討論檔案授權。

URL 授權的範圍

UrlAuthorizationModule是屬於 ASP.NET 執行時間一部分的 Managed 程式碼。 在 Microsoft Internet Information Services (IIS) Web 服務器 7 版之前,IIS 的 HTTP 管線與 ASP.NET 執行時間管線之間有不同的屏障。 簡單地說,在 IIS 6 和更早版本中,ASP。 UrlAuthorizationModule 只有在將要求從 IIS 委派給 ASP.NET 執行時間時,才會執行 NET。 根據預設,IIS 會處理靜態內容本身,例如 HTML 頁面和 CSS、JavaScript 和影像檔,而且只有在要求副檔名 .aspx 為 、 .asmx.ashx 的頁面時,才會將要求交給 ASP.NET 執行時間。

不過,IIS 7 允許整合式 IIS 和 ASP.NET 管線。 透過幾個組態設定,您可以設定 IIS 7 來叫 UrlAuthorizationModule所有 要求的 ,這表示可以針對任何類型的檔案定義 URL 授權規則。 此外,IIS 7 也包含自己的 URL 授權引擎。 如需 ASP.NET 整合和 IIS 7 原生 URL 授權功能的詳細資訊,請參閱 瞭解 IIS7 URL 授權。 如需更深入的 ASP.NET 和 IIS 7 整合,請挑選 Shahram Khosravi 書籍、 專業 IIS 7 和 ASP.NET 整合式程式設計 ( ISBN:978-0470152539) 。

簡單地說,在 IIS 7 之前的版本中,URL 授權規則只會套用至 ASP.NET 執行時間所處理的資源。 但使用 IIS 7 時,可以使用 IIS 的原生 URL 授權功能或整合 ASP。NET 進入 UrlAuthorizationModule IIS 的 HTTP 管線,藉此將這項功能延伸至所有要求。

注意

ASP 的一些細微但重要差異。NET 和 UrlAuthorizationModule IIS 7 的 URL 授權功能會處理授權規則。 本教學課程不會檢查 IIS 7 的 URL 授權功能,或與 相較之下 UrlAuthorizationModule 剖析授權規則的差異。 如需這些主題的詳細資訊,請參閱 MSDN 或 www.iis.net上的 IIS 7 檔。

步驟 1:在 中定義 URL 授權規則Web.config

UrlAuthorizationModule 根據應用程式組態中定義的 URL 授權規則,判斷是否要授與或拒絕特定身分識別所要求資源的存取權。 授權規則會以 和 <deny> 子項目的形式 <allow> 在 元素中拼出<authorization>。 每個 <allow><deny> 子項目都可以指定:

  • 特定使用者
  • 以逗號分隔的使用者清單
  • 所有匿名使用者,以問號表示 (?)
  • 所有使用者,以星號 (*) 表示

下列標記說明如何使用 URL 授權規則來允許使用者 Tito 和 Scott,並拒絕所有其他專案:

<authorization>
 <allow users="Tito, Scott" />
 <deny users="*" />
</authorization>

元素 <allow> 會定義允許的使用者 - Tito 和 Scott - ,而 <deny> 元素會指示 所有使用者 遭到拒絕。

注意

<allow><deny> 元素也可以指定角色的授權規則。 我們將在未來的教學課程中檢查角色型授權。

下列設定會將存取權授與 Sam 以外的任何人 (,包括匿名訪客) :

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

若要只允許已驗證的使用者,請使用下列組態,拒絕存取所有匿名使用者:

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

授權規則定義于 中的 Web.config 元素內 <system.web> ,並套用至 Web 應用程式中的所有 ASP.NET 資源。 應用程式通常會有不同的不同區段的授權規則。 例如,在電子商務網站上,所有訪客都可以使用產品、查看產品評論、搜尋類別目錄等等。 不過,只有已驗證的使用者才能連線到簽出或頁面,以管理一個寄送歷程記錄。 此外,網站中可能有部分只能由選取的使用者存取,例如網站管理員。

ASP.NET 可讓您輕鬆地為網站中的不同檔案和資料夾定義不同的授權規則。 根資料夾檔案 Web.config 中指定的授權規則會套用至網站中的所有 ASP.NET 資源。 不過,您可以使用 區段新增 Web.config<authorization> 來覆寫特定資料夾的這些預設授權設定。

讓我們更新網站,讓只有已驗證的使用者才能流覽資料夾中的 ASP.NET 網頁 Membership 。 若要達成此目的,我們需要將檔案新增 Web.configMembership 資料夾,並將其授權設定設為拒絕匿名使用者。 以滑鼠右鍵按一下 Membership 方案總管中的資料夾,從操作功能表選擇 [新增專案] 功能表,然後新增名為 Web.config 的新 Web 組態檔。

將Web.config檔案新增至成員資格資料夾

圖 3:將檔案 Web.config 新增至 Membership 資料夾 (按一下即可檢視大小完整的影像)

此時,您的專案應該包含兩 Web.config 個檔案:一個位於根目錄中,另一個位於 Membership 資料夾中。

您的應用程式現在應該包含兩個Web.config檔案

圖 4:您的應用程式現在應該包含兩 Web.config 個檔案, (按一下即可檢視完整大小的映射)

更新 資料夾中的 Membership 組態檔,使其禁止存取匿名使用者。

<?xml version="1.0"?>
<configuration>
 <system.web>
 <authorization>
 <deny users="?" />
 </authorization>
 </system.web>
</configuration>

就是這麼簡單!

若要測試這項變更,請流覽瀏覽器中的首頁,並確定您已登出。由於 ASP.NET 應用程式的預設行為是允許所有訪客,而且因為我們未對根目錄的 Web.config 檔案進行任何授權修改,因此我們可以以匿名訪客身分造訪根目錄中的檔案。

按一下左側資料行中找到的 [建立使用者帳戶] 連結。 這會帶您前往 ~/Membership/CreatingUserAccounts.aspxWeb.config由於 資料夾中的 Membership 檔案會定義禁止匿名存取的授權規則,因此會 UrlAuthorizationModule 中止要求並傳回 HTTP 401 未經授權狀態。 會將 FormsAuthenticationModule 此修改為 302 重新導向狀態,並將我們傳送至登入頁面。 請注意,我們嘗試存取 () CreatingUserAccounts.aspx 的頁面會透過 ReturnUrl querystring 參數傳遞至登入頁面。

由於 URL 授權規則禁止匿名存取,我們會重新導向至登入頁面

圖 5:由於 URL 授權規則禁止匿名存取,我們會重新導向至登入頁面 (按一下以檢視大小完整的影像)

成功登入時,我們會重新導向至 CreatingUserAccounts.aspx 頁面。 這次允許 UrlAuthorizationModule 存取頁面,因為我們不再匿名。

將 URL 授權規則套用至特定位置

<system.web> 段中 Web.config 定義的授權設定會套用至該目錄中的所有 ASP.NET 資源及其子目錄, (直到其他 Web.config 檔案) 覆寫為止。 不過,在某些情況下,我們可能會希望指定目錄中的所有 ASP.NET 資源都有特定的授權設定,但一或兩個特定頁面除外。 這可以藉由在 中 Web.config 新增 元素,並將其指向授權規則不同的檔案,並在其中定義其唯一 <location> 授權規則來達成此目的。

為了說明如何使用 <location> 元素覆寫特定資源的組態設定,讓我們自訂授權設定,讓只有 Tito 可以流覽 CreatingUserAccounts.aspx 。 若要達成此目的,請將專案新增 <location>Membership 資料夾的 Web.config 檔案,並更新其標記,使其看起來如下:

<?xml version="1.0"?>
<configuration>
 <system.web>
 <authorization>
 <deny users="?" />
 </authorization>
 </system.web>

 <location path="CreatingUserAccounts.aspx">
 <system.web>
 <authorization>
 <allow users="Tito" />
 <deny users="*" />
 </authorization>
 </system.web>
 </location>
</configuration>

中的 <authorization><system.web> 元素會定義資料夾及其子資料夾中 ASP.NET 資源 Membership 的預設 URL 授權規則。 元素 <location> 可讓我們覆寫特定資源的這些規則。 在上述標記中, <location> 元素會參考 CreatingUserAccounts.aspx 頁面,並指定其授權規則,例如允許 Tito,但拒絕其他人。

若要測試此授權變更,請從以匿名使用者身分流覽網站開始。 如果您嘗試流覽資料夾中的任何頁面 Membership ,例如 UserBasedAuthorization.aspx ,將會 UrlAuthorizationModule 拒絕要求,而且系統會將您重新導向至登入頁面。 如同 Scott 一樣登入之後,您可以流覽資料夾中的任何頁面 Membership但 除外CreatingUserAccounts.aspx 。 嘗試以 CreatingUserAccounts.aspx 任何人身分登入,但 Tito 會導致未經授權的存取嘗試,將您重新導向回登入頁面。

注意

元素 <location> 必須出現在組態的 <system.web> 元素之外。 您必須針對您想要覆寫其授權設定的每個資源使用不同的 <location> 元素。

查看 如何使用 UrlAuthorizationModule 授權規則來授與或拒絕存取權

UrlAuthorizationModule 判斷是否一次分析一個 URL 授權規則,從第一個 URL 開始,並正常運作,來授權特定 URL 的特定身分識別。 一旦找到相符專案,使用者就會被授與或拒絕存取權,視在 或 <deny> 專案中找到 <allow> 相符專案而定。 如果找不到相符專案,則會將存取權授與使用者。 因此,如果您想要限制存取,您必須使用 元素作為 URL 授權組態中的最後一個專案 <deny>如果您省略<deny>元素,所有使用者都會獲得存取權。

若要進一步瞭解 用來 UrlAuthorizationModule 判斷授權的程式,請考慮我們稍早在此步驟中查看的範例 URL 授權規則。 第一個 <allow> 規則是允許存取 Tito 和 Scott 的專案。 第二個 <deny> 規則是拒絕所有人存取的專案。 如果匿名使用者造訪,首先 UrlAuthorizationModule 會詢問匿名的 Scott 或 Tito 嗎? 答案顯然是 [否],因此它會繼續進行第二個規則。 匿名是否在每個人的集合中? 因為這裡的答案是 [是],所以 <deny> 規則會生效,而訪客會重新導向至登入頁面。 同樣地,如果 Jisun 正在造訪,則 UrlAuthorizationModule 一開始會詢問 Jisun 是否為 Scott 或 Tito? 因為她不是,所以 UrlAuthorizationModule 會繼續進行第二個問題:Jisun 是否在每個人的集合中? 她也拒絕存取。 最後,如果 Tito 造訪,所 UrlAuthorizationModule 提出的第一個問題是肯定答案,因此會授與 Tito 的存取權。

由於 會 UrlAuthorizationModule 從上而下處理授權規則,因此在任何相符專案停止時,請務必讓更特定的規則在較不特定的規則之前。 也就是說,若要定義禁止 Jisun 和匿名使用者的授權規則,但允許所有其他已驗證的使用者,您會從影響 Jisun 的最特定規則開始,然後繼續執行較不特定的規則-允許所有其他已驗證的使用者,但拒絕所有匿名使用者。 下列 URL 授權規則會先拒絕 Jisun,然後拒絕任何匿名使用者,以實作此原則。 Jisun 以外的任何已驗證使用者都會被授與存取權,因為這些語句都不會 <deny> 相符。

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

步驟 2:修正未經授權、已驗證使用者的工作流程

As we discussed earlier in this tutorial in the A Look at the URL Authorization Workflow section, anytime an unauthorized request transpires, the UrlAuthorizationModule aborts the request and returns an HTTP 401 Unauthorized status. 此 401 狀態會由 FormsAuthenticationModule 修改為 302 重新導向狀態,將使用者傳送至登入頁面。 即使使用者經過驗證,此工作流程仍會在任何未經授權的要求上發生。

將已驗證的使用者傳回登入頁面可能會混淆,因為它們已經登入系統。 透過稍微工作,我們可以將發出未經授權的要求的使用者重新導向至說明他們嘗試存取受限制頁面的頁面,藉此改善此工作流程。

首先,在名為 UnauthorizedAccess.aspx 的 Web 應用程式的根資料夾中建立新的 ASP.NET 網頁;別忘了將此頁面與 Site.master 主版頁面產生關聯。 建立此頁面之後,請移除參考 LoginContent ContentPlaceHolder 的內容控制項,以便顯示主版頁面的預設內容。 接下來,新增說明情況的訊息,也就是使用者嘗試存取受保護的資源。 新增這類訊息之後, UnauthorizedAccess.aspx 頁面的宣告式標記看起來應該類似下列內容:

<%@ Page Language="VB" MasterPageFile="~/Site.master" AutoEventWireup="false"
CodeFile="UnauthorizedAccess.aspx.cs" Inherits="UnauthorizedAccess"
Title="Untitled Page" %>

<asp:Content ID="Content1" ContentPlaceHolderID="MainContent"
Runat="Server">
 <h2>Unauthorized Access</h2>
 <p>
 You have attempted to access a page that you are not authorized to view.
 </p>
 <p>
 If you have any questions, please contact the site administrator.
 </p>
</asp:Content>

我們現在需要改變工作流程,如此一來,如果未經授權的要求是由已驗證的使用者執行,他們就會傳送至 UnauthorizedAccess.aspx 頁面,而不是登入頁面。 將未經授權的要求重新導向至登入頁面的邏輯會在 類別的私人 FormsAuthenticationModule 方法內,因此我們無法自訂此行為。 不過,我們可以執行的動作是將自己的邏輯新增至登入頁面,以視需要將使用者重新導向至 UnauthorizedAccess.aspx

當 將 FormsAuthenticationModule 未經授權的訪客重新導向至登入頁面時,它會將要求、未經授權的 URL 附加至名稱 ReturnUrl 為 的查詢字串。 例如,如果未經授權的使用者嘗試造訪 OnlyTito.aspx ,則會 FormsAuthenticationModule 將它們重新導向至 Login.aspx?ReturnUrl=OnlyTito.aspx 。 因此,如果已驗證的使用者已使用包含 ReturnUrl 參數的 querystring 連線到登入頁面,則我們知道這個未經驗證的使用者剛嘗試造訪她未獲授權檢視的頁面。 在這種情況下,我們想要將她重新導向至 UnauthorizedAccess.aspx

若要完成此作業,請將下列程式碼新增至登入頁面的 Page_Load 事件處理常式:

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
 If Not Page.IsPostBack Then
 If Request.IsAuthenticated AndAlso Not String.IsNullOrEmpty(Request.QueryString("ReturnUrl")) Then
 ' This is an unauthorized, authenticated request...
 Response.Redirect("~/UnauthorizedAccess.aspx")
 End If
 End If
End Sub

上述程式碼會將已驗證、未經授權的使用者重新導向至 UnauthorizedAccess.aspx 頁面。 若要查看此邏輯運作情形,請以匿名訪客身分造訪網站,然後按一下左側資料行中的 [建立使用者帳戶] 連結。 這會帶您前往 ~/Membership/CreatingUserAccounts.aspx 頁面,我們在步驟 1 中設定為只允許存取 Tito。 由於禁止匿名使用者,因此會將 FormsAuthenticationModule 我們重新導向回登入頁面。

此時,我們會匿名,因此 Request.IsAuthenticated 會傳 False 回 ,而且不會重新導向至 UnauthorizedAccess.aspx 。 相反地,會顯示登入頁面。 以 Tito 以外的使用者身分登入,例如 Bruce。 輸入適當的認證之後,登入頁面會將我們重新導向回 ~/Membership/CreatingUserAccounts.aspx 。 不過,由於此頁面只能供 Tito 存取,因此我們未經授權的檢視頁面,並立即返回登入頁面。 不過,這次會 Request.IsAuthenticated 傳回 True (,而且 ReturnUrl 查詢字串參數存在) ,因此我們會重新導向至 UnauthorizedAccess.aspx 頁面。

已驗證,未經授權的使用者會重新導向至 UnauthorizedAccess.aspx

圖 6:已驗證、未經授權的使用者會重新導向至 UnauthorizedAccess.aspx (按一下以檢視完整大小的映射)

此自訂工作流程藉由縮短圖 2 中所述的迴圈,呈現更合理且直接的使用者體驗。

步驟 3:根據目前登入的使用者限制功能

URL 授權可讓您輕鬆地指定粗略的授權規則。 如步驟 1 中所見,透過 URL 授權,我們可以簡潔地陳述允許的身分識別,以及哪些身分識別遭到拒絕,而無法檢視資料夾中的特定頁面或所有頁面。 不過,在某些情況下,我們可能會想要允許所有使用者流覽頁面,但根據流覽頁面的使用者限制頁面的功能。

請考慮允許已驗證訪客檢閱其產品的電子商務網站案例。 當匿名使用者流覽產品的頁面時,他們只會看到產品資訊,而不會有機會離開評論。 不過,流覽相同頁面的已驗證使用者會看到檢閱介面。 如果已驗證的使用者尚未檢閱此產品,介面會讓他們提交檢閱;否則會顯示他們先前提交的檢閱。 若要進一步進行此案例,產品頁面可能會顯示其他資訊,並為適用于電子商務公司的使用者提供擴充功能。 例如,產品頁面可能會列出庫存,並包含選項,以在員工造訪時編輯產品的價格和描述。

這類細微授權規則可以宣告式或以程式設計方式實作 (,或透過兩個) 的一些組合來實作。 在下一節中,我們將瞭解如何透過 LoginView 控制項實作細微授權。 接下來,我們將探索程式設計技術。 不過,在我們可以查看套用細微授權規則之前,我們必須先建立一個頁面,其功能取決於流覽者。

讓我們建立一個頁面,以列出 GridView 內特定目錄中的檔案。 除了列出每個檔案的名稱、大小和其他資訊之外,GridView 也會包含兩個 LinkButtons 資料行:一個標題為 View,另一個標題為 Delete。 如果按一下 [檢視連結][按鈕],則會顯示所選檔案的內容;如果按一下 [刪除 LinkButton],則會刪除檔案。 讓我們一開始建立此頁面,使其檢視和刪除功能可供所有使用者使用。 在 [使用 LoginView 控制項和以程式設計方式限制功能] 區段中,我們將瞭解如何根據流覽頁面的使用者啟用或停用這些功能。

注意

我們即將建置的 [ASP.NET] 頁面會使用 GridView 控制項來顯示檔案清單。 由於本教學課程系列著重于表單驗證、授權、使用者帳戶和角色,我不想花太多時間討論 GridView 控制項的內部工作。 雖然本教學課程提供設定此頁面的特定逐步指示,但不會深入探討為何進行特定選擇的原因,或轉譯輸出上特定屬性有何影響。 如需 GridView 控制項的完整檢查,請參閱 在 ASP.NET 2.0 教學課程系列中使用資料。

首先,開啟 資料夾中的 UserBasedAuthorization.aspxMembership 檔案,並將 GridView 控制項新增至名為 FilesGrid 的頁面。 從 GridView 的智慧標籤中,按一下 [編輯資料行] 連結以啟動 [欄位] 對話方塊。 從這裡取消核取左下角的 [自動產生欄位] 核取方塊。 接下來,新增 [選取] 按鈕、[刪除] 按鈕,以及左上角的兩個 BoundFields, ([選取和刪除] 按鈕位於 CommandField 類型) 下。 將 [選取] 按鈕的 SelectText 屬性設定為 [檢視],並將第一個 BoundField 的 HeaderTextDataField 屬性設定為 [名稱]。 將第二個 BoundField 的 HeaderText 屬性設定為 Size in Bytes,其 DataField 屬性設定為 Length,其 屬性設定為 {0:N0} ,並將 DataFormatString 屬性 HtmlEncode 設定為 False。

設定 GridView 的資料行之後,按一下 [確定] 以關閉 [欄位] 對話方塊。 從屬性視窗,將 GridView 的 DataKeyNames 屬性設定為 FullName 。 此時 GridView 的宣告式標記看起來應該如下所示:

<asp:GridView ID="FilesGrid" DataKeyNames="FullName" runat="server" AutoGenerateColumns="False">
 <Columns>
 <asp:CommandField SelectText="View" ShowSelectButton="True"/>
 <asp:CommandField ShowDeleteButton="True" />
 <asp:BoundField DataField="Name" HeaderText="Name" />
 <asp:BoundField DataField="Length" DataFormatString="{0:N0}"
 HeaderText="Size in Bytes" HtmlEncode="False" />
 </Columns>
</asp:GridView>

建立 GridView 的標記之後,我們已準備好撰寫程式碼,以擷取特定目錄中的檔案,並將其系結至 GridView。 將下列程式碼新增至頁面的 Page_Load 事件處理常式:

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
 If Not Page.IsPostBack Then
 Dim appPath As String = Request.PhysicalApplicationPath
 Dim dirInfo As New DirectoryInfo(appPath)

 Dim files() As FileInfo = dirInfo.GetFiles()

 FilesGrid.DataSource = files
 FilesGrid.DataBind()
 End If
End Sub

上述程式碼會DirectoryInfo 使用 類別來取得應用程式根資料夾中的檔案清單。 方法 GetFiles()會將目錄中的所有檔案當做 物件的陣列FileInfo傳回,然後系結至 GridView。 物件 FileInfo 具有各種屬性,例如 NameLengthIsReadOnly 等。 如您可以從其宣告式標記中看到,GridView 只會 Name 顯示 和 Length 屬性。

注意

DirectoryInfoFileInfo 類別位於命名空間中 System.IO。 因此,您必須在這些類別名稱前面加上其命名空間名稱,或透過 Imports System.IO) 將命名空間匯入類別檔案 (。

請花點時間透過瀏覽器流覽此頁面。 它會顯示位於應用程式根目錄中的檔案清單。 按一下任何 View 或 Delete LinkButtons 會導致回傳,但不會發生任何動作,因為我們尚未建立必要的事件處理常式。

GridView 列出 Web 應用程式根目錄中的檔案

圖 7:GridView 會列出 Web 應用程式根目錄中的檔案, (按一下即可檢視大小完整的映射)

我們需要一個方法來顯示所選檔案的內容。 返回 Visual Studio,並在 GridView 上方新增名為 FileContents 的 TextBox。 將其 TextMode 屬性分別設定為 MultiLine ,以及其 ColumnsRows 屬性分別設定為 95% 和 10。

<asp:TextBox ID="FileContents" runat="server" Rows="10"
TextMode="MultiLine" Width="95%"></asp:TextBox>

接下來,建立 GridView事件的 SelectedIndexChanged事件處理常式,並新增下列程式碼:

Protected Sub FilesGrid_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles FilesGrid.SelectedIndexChanged
 ' Open the file and display it
 Dim fullFileName As String = FilesGrid.SelectedValue.ToString()
 Dim contents As String = File.ReadAllText(fullFileName)
 FileContents.Text = contents
End Sub

此程式碼會使用 GridView 的 SelectedValue 屬性來判斷所選檔案的完整檔案名。 在內部, DataKeys 會參考集合以取得 SelectedValue ,因此您必須將 GridView 的 DataKeyNames 屬性設定為 Name,如此步驟稍早所述。 類別 File是用來將選取的檔案內容讀入字串中,然後指派給 FileContents TextBox Text 的 屬性,進而在頁面上顯示所選檔案的內容。

選取的檔案內容會顯示在 TextBox 中

圖 8:選取的檔案內容會顯示在 TextBox (按一下即可檢視大小完整的影像)

注意

如果您檢視包含 HTML 標籤的檔案內容,然後嘗試檢視或刪除檔案,您會收到 HttpRequestValidationException 錯誤。 這是因為在回傳時,TextBox 的內容會傳回至網頁伺服器。 根據預設,每當偵測到潛在危險回傳內容,例如 HTML 標籤時,ASP.NET 就會 HttpRequestValidationException 引發錯誤。 若要停用此錯誤發生,請藉由將 新增 ValidateRequest="false"@Page 指示詞,關閉頁面的要求驗證。 如需要求驗證的優點,以及停用要求時應採取哪些預防措施的詳細資訊,請參閱 要求驗證 - 防止腳本攻擊

最後,為 GridView 的事件新增具有下列程式碼的RowDeleting事件處理常式:

Protected Sub FilesGrid_RowDeleting(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewDeleteEventArgs)Handles FilesGrid.RowDeleting
 Dim fullFileName As String = FilesGrid.DataKeys(e.RowIndex).Value.ToString()
 FileContents.Text = String.Format("You have opted to delete {0}.", fullFileName)

 ' To actually delete the file, uncomment the following line
 ' File.Delete(fullFileName)
End Sub

程式碼只會在 TextBox 中 FileContents 顯示要刪除之檔案的完整名稱, 而不會 實際刪除檔案。

按一下 [刪除] 按鈕並不會實際刪除檔案

圖 9:按一下 [刪除] 按鈕不會實際刪除檔案 (按一下即可檢視大小完整的影像)

在步驟 1 中,我們已設定 URL 授權規則,禁止匿名使用者檢視資料夾中的頁面 Membership 。 為了更進一步展現細微的驗證,讓我們允許匿名使用者流覽 UserBasedAuthorization.aspx 頁面,但功能有限。 若要開啟此頁面供所有使用者存取,請將下列 <location> 元素新增至 Web.config 資料夾中的 Membership 檔案:

<location path="UserBasedAuthorization.aspx">
 <system.web>
 <authorization>
 <allow users="*" />
 </authorization>
 </system.web>
</location>

新增這個專案 <location> 之後,請登出網站來測試新的 URL 授權規則。 身為匿名使用者,您應該允許流覽 UserBasedAuthorization.aspx 頁面。

目前,任何已驗證或匿名的使用者都可以流覽 UserBasedAuthorization.aspx 頁面,並檢視或刪除檔案。 讓我們讓它成為這樣,只有經過驗證的使用者才能檢視檔案的內容,而且只有 Tito 可以刪除檔案。 這類精細的授權規則可以宣告方式、以程式設計方式或透過這兩種方法的組合來套用。 讓我們使用宣告式方法來限制誰可以檢視檔案的內容;我們將使用程式設計方法來限制誰可以刪除檔案。

使用 LoginView 控制項

如過去教學課程中所見,LoginView 控制項對於顯示已驗證和匿名使用者的不同介面很有用,並提供簡單的方法來隱藏匿名使用者無法存取的功能。 由於匿名使用者無法檢視或刪除檔案,因此我們只需要在驗證的使用者流覽頁面時顯示 FileContents TextBox。 若要達成此目的,請將 LoginView 控制項新增至頁面、將它命名為 LoginViewForFileContentsTextBox ,然後將 TextBox 的宣告式標記移至 FileContents LoginView 控制項的 LoggedInTemplate

<asp:LoginView ID=" LoginViewForFileContentsTextBox " runat="server">
 <LoggedInTemplate>
 <p>
 <asp:TextBox ID="FileContents" runat="server" Rows="10"
 TextMode="MultiLine" Width="95%"></asp:TextBox>
 </p>
 </LoggedInTemplate>
</asp:LoginView>

LoginView 範本中的 Web 控制項無法從程式碼後置類別直接存取。 例如, FilesGrid GridView 的 SelectedIndexChangedRowDeleting 事件處理常式目前參考 TextBox 控制項的程式 FileContents 代碼如下:

FileContents.Text = text

不過,此程式碼已不再有效。 無法直接存取將 TextBox 移至 FileContentsLoggedInTemplate TextBox。 相反地,我們必須使用 FindControl("controlId") 方法來以程式設計方式參考 控制項。 FilesGrid更新事件處理常式以參考 TextBox,如下所示:

Dim FileContentsTextBox As TextBox = CType(LoginViewForFileContentsTextBox.FindControl("FileContents"),TextBox)
FileContentsTextBox.Text = text

將 TextBox 移至 LoginView 的 LoggedInTemplate ,並更新頁面的程式碼以使用 FindControl("controlId") 模式參考 TextBox 之後,請以匿名使用者身分流覽頁面。 如圖 10 所示, FileContents TextBox 不會顯示。 不過,仍會顯示 View LinkButton。

LoginView 控制項只會轉譯已驗證使用者的 FileContents TextBox

圖 10:LoginView 控制項只會呈現 FileContents 已驗證使用者的 TextBox, (按一下即可檢視大小完整的影像)

隱藏匿名使用者的 [檢視] 按鈕的其中一種方式是將 GridView 欄位轉換成 TemplateField。 這會產生範本,其中包含 View LinkButton 的宣告式標記。 然後,我們可以將 LoginView 控制項新增至 TemplateField,並將 LinkButton 放在 LoginView 的 中 LoggedInTemplate ,藉此隱藏匿名訪客的 [檢視] 按鈕。 若要完成此動作,請按一下 GridView 智慧標籤中的 [編輯資料行] 連結,以啟動 [欄位] 對話方塊。 接下來,從左下角清單中選取 [選取] 按鈕,然後按一下 [將此欄位轉換為 TemplateField] 連結。 這麼做會從下列專案修改欄位的宣告式標記:

<asp:CommandField SelectText="View" ShowSelectButton="True"/>

變更為:

<asp:TemplateField ShowHeader="False">
 <ItemTemplate>
 <asp:LinkButton ID="LinkButton1" runat="server" CausesValidation="False"
 CommandName="Select" Text="View"></asp:LinkButton>
 </ItemTemplate>
</asp:TemplateField>

此時,我們可以將 LoginView 新增至 TemplateField。 下列標記只會針對已驗證的使用者顯示 View LinkButton。

<asp:TemplateField ShowHeader="False">
 <ItemTemplate>
 <asp:LoginView ID="LoginView1" runat="server">
 <LoggedInTemplate>
 <asp:LinkButton ID="LinkButton1" runat="server" CausesValidation="False"
 CommandName="Select" Text="View"></asp:LinkButton>
 </LoggedInTemplate>
 </asp:LoginView>
 </ItemTemplate>
</asp:TemplateField>

如圖 11 所示,即使隱藏資料行內的 View LinkButton,最終結果也不會像檢視資料行一樣顯示。 我們將探討如何隱藏整個 GridView 資料行 (,而不只是下一節中的 LinkButton) 。

LoginView 控制項會隱藏匿名訪客的檢視連結按鈕

圖 11:LoginView 控制項會隱藏匿名訪客的檢視連結按鈕, (按一下即可檢視大小完整的影像)

以程式設計方式限制功能

在某些情況下,宣告式技術不足以限制頁面的功能。 例如,某些頁面功能的可用性可能取決於流覽頁面的使用者是匿名還是已驗證的準則。 在這種情況下,可以透過程式設計方式顯示或隱藏各種使用者介面元素。

為了以程式設計方式限制功能,我們需要執行兩項工作:

  1. 判斷流覽頁面的使用者是否可以存取功能,以及
  2. 根據使用者是否可以存取有問題的功能,以程式設計方式修改使用者介面。

為了示範這兩項工作的應用程式,我們只允許 Tito 從 GridView 刪除檔案。 然後,我們的第一個工作是判斷它是否為流覽頁面的 Tito。 一旦決定之後,我們需要隱藏 (或顯示 GridView 的 Delete 資料行) 。 GridView 的資料行可透過其 Columns 屬性存取;只有當資料 Visible 行的 屬性設定 True 為 (預設) 時,才會轉譯資料行。

將下列程式碼新增至 Page_Load 事件處理常式,再將資料系結至 GridView:

' Is this Tito visiting the page?
Dim userName As String = User.Identity.Name
If String.Compare(userName, "Tito", True) = 0 Then
 ' This is Tito, SHOW the Delete column
 FilesGrid.Columns(1).Visible = True
Else
 ' This is NOT Tito, HIDE the Delete column
 FilesGrid.Columns(1).Visible = False
End If

如我們在 表單驗證概 觀教學課程中所討論, User.Identity.Name 傳回身分識別的名稱。 這會對應至登入控制項中輸入的使用者名稱。 如果是流覽頁面的 Tito,GridView 的第二 Visible 個數據行屬性會設定 True 為 ,否則會設定為 False 。 最終結果是,當 Tito 以外的人造訪頁面時,另一個已驗證的使用者或匿名使用者,[刪除] 資料行不會轉譯 (請參閱圖 12) ;不過,當 Tito 流覽頁面時,[刪除] 資料行會 (請參閱圖 13) 。

當 Tito 以外的人造訪時,[刪除資料行] 不會轉譯 (,例如暴力密碼)

圖 12:刪除資料行在 Tito 以外的人流覽時不會轉譯,例如暴力密碼 () (按一下即可檢視大小完整的影像)

[刪除資料行] 會針對 Tito 轉譯

圖 13:[刪除資料行] 會針對 Tito 轉譯 (按一下以檢視大小完整的影像)

步驟 4:將授權規則套用至類別和方法

在步驟 3 中,我們不允許匿名使用者檢視檔案的內容,並禁止所有使用者但 Tito 刪除檔案。 這是透過宣告式和程式設計技術,隱藏未經授權的訪客相關聯的使用者介面元素來完成。 在我們的簡單範例中,正確隱藏使用者介面元素很簡單,但更複雜的網站可能有許多不同的方式可執行相同的功能呢? 在將該功能限制為未經授權的使用者時,如果我們忘記隱藏或停用所有適用的使用者介面元素,會發生什麼事?

確保未經授權的使用者無法存取特定功能片段的簡單方式,就是使用PrincipalPermission 屬性裝飾該類別或方法。 當 .NET 執行時間使用類別或執行其中一個方法時,它會檢查以確保目前的安全性內容具有使用類別或執行方法的許可權。 屬性 PrincipalPermission 提供一種機制,讓我們可以定義這些規則。

讓我們示範如何使用 PrincipalPermission GridView SelectedIndexChangedRowDeleting 事件處理常式上的 屬性,分別禁止 Tito 以外的匿名使用者和使用者執行。 我們只需要在每個函式定義上新增適當的屬性:

<PrincipalPermission(SecurityAction.Demand, Authenticated:=True)> _
Protected Sub FilesGrid_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles FilesGrid.SelectedIndexChanged
 ...
End Sub

<PrincipalPermission(SecurityAction.Demand, Name:="Tito")> _
Protected Sub FilesGrid_RowDeleting(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewDeleteEventArgs) Handles FilesGrid.RowDeleting
 ...
End Sub

事件處理常式的 SelectedIndexChanged 屬性會指示只有已驗證的使用者可以執行事件處理常式,因為事件處理常式上的 RowDeleting 屬性會將執行限制為 Tito。

注意

屬性可以套用至類別、方法、屬性或事件。 新增屬性時,它必須是類別、方法、屬性或事件宣告語句的一部分。 由於 Visual Basic 使用分行符號做為語句分隔符號,因此屬性必須出現在與宣告相同的行上,或是以行接續字元直接出現在該行上方, (底線) 。 在上述程式碼片段中,行接續字元是用來將 屬性放在一行上,並將方法宣告放在另一行。

如果 Tito 以外的使用者嘗試執行 RowDeleting 事件處理常式,或非驗證的使用者嘗試執行 SelectedIndexChanged 事件處理常式,則 .NET 執行時間會引發 SecurityException

如果安全性內容未獲授權執行方法,則會擲回 SecurityException

圖 14:如果安全性內容未獲授權執行方法,則會 SecurityException 擲回 (Click 以檢視大小完整的映射)

注意

若要允許多個安全性內容存取類別或方法,請使用每個安全性內容的屬性裝飾類別或方法 PrincipalPermission 。 也就是說,若要允許 Tito 和 Bruce 同時執行 RowDeleting 事件處理常式,請新增兩個PrincipalPermission 屬性:

<PrincipalPermission(SecurityAction.Demand, Name:="Tito")> _

<PrincipalPermission(SecurityAction.Demand, Name:="Bruce")> _

除了 ASP.NET 網頁之外,許多應用程式也有包含各種層級的架構,例如商務邏輯和資料存取層。 這些層通常會實作為類別庫,並提供類別和方法來執行商務邏輯和資料相關功能。 屬性 PrincipalPermission 適用于將授權規則套用至這些層。

如需使用 PrincipalPermission 屬性定義類別和方法授權規則的詳細資訊,請參閱Scott Guthrie的部落格文章:使用 PrincipalPermissionAttributes 將授權規則新增至商務和資料層

摘要

在本教學課程中,我們探討如何套用使用者型授權規則。 我們開始使用 ASP。NET 的 URL 授權架構。 在每個要求上,ASP.NET 引擎 UrlAuthorizationModule 會檢查應用程式組態中定義的 URL 授權規則,以判斷身分識別是否有權存取所要求的資源。 簡單來說,URL 授權可讓您輕鬆地指定特定頁面的授權規則,或針對特定目錄中的所有頁面指定授權規則。

URL 授權架構會逐頁套用授權規則。 透過 URL 授權,要求身分識別有權存取特定資源。 不過,許多案例都會呼叫更精細的授權規則。 我們不需要定義允許存取頁面的人員,可能需要讓每個人都存取頁面,但視流覽頁面的使用者而定,顯示不同的資料或提供不同的功能。 頁面層級授權通常牽涉到隱藏特定使用者介面元素,以防止未經授權的使用者存取禁止的功能。 此外,也可以使用屬性來限制對類別的存取,以及針對特定使用者執行其方法。

快樂的程式設計!

深入閱讀

如需本教學課程中討論之主題的詳細資訊,請參閱下列資源:

關於作者

Scott Mitchell 是多個 ASP/ASP.NET 書籍的作者,且 4GuysFromRolla.com 的作者,自 1998 年以來,已與 Microsoft Web 技術合作。 Scott 是獨立顧問、訓練員和作者。 他的最新書籍是 Sams 在 24 小時內自行 ASP.NET 2.0。 您可以在 或 透過在 的 http://ScottOnWriting.NET 部落格連線 mitchell@4guysfromrolla.com 到 Scott。

特別感謝

本教學課程系列是由許多實用的檢閱者檢閱。 有興趣檢閱即將推出的 MSDN 文章嗎? 如果是,請將一行 mitchell@4GuysFromRolla.com 放在 。