注意
這不是這篇文章的最新版本。 如需目前的版本,請參閱 本文的 .NET 9 版本。
警告
不再支援此版本的 ASP.NET Core。 如需詳細資訊,請參閱 .NET 和 .NET Core 支持原則。 如需目前的版本,請參閱 本文的 .NET 9 版本。
本文說明 ASP.NET Core 對於在 Blazor 應用程式中設定及管理安全性的支援。
Blazor 會使用現有的 ASP.NET 核心驗證機制來建立使用者的身分識別。 確切的機制會取決於 Blazor 應用程式的裝載方式 (伺服器端或用戶端)。
在 Blazor 應用程式中,授權碼運行於伺服器端和用戶端時,其安全性情境有所不同。 若是在伺服器上執行的授權碼,授權檢查可針對應用程式和元件的區域強制執行存取規則。 由於用戶端的程式碼執行可能會遭到竄改,因此無法保證在用戶端上執行的授權碼會絕對強制執行存取規則或控制用戶端內容的顯示。
如果必須確保授權規則的強制執行,請勿將授權檢查實作於用戶端程式碼中。 建立一個僅依賴伺服器端渲染 (SSR) 進行授權檢查和規則執行的 Blazor Web App。
如果必須確保授權規則強制執行以及資料與程式碼的安全性,請勿開發用戶端應用程式。 建置 Blazor Server 應用程式。
Razor Pages 授權慣例不會套用至路由式 Razor 元件。 如果一個無法路由的 Razor 元件 被內嵌在 Razor Pages 應用程式的頁面中,頁面的授權慣例會間接影響該 Razor 元件以及頁面內容的其餘部分。
ASP.NET Core Identity 的設計目的是要在 HTTP 要求和回應通訊的情境中運作,而這通常並不是 Blazor 應用程式的用戶端-伺服器通訊模型。 使用 ASP.NET Core Identity 來管理使用者的 ASP.NET Core 應用程式,應選擇使用 Razor Pages 而不是 Razor 元件,以實現 Identity 相關介面功能,例如使用者註冊、登入、登出及其他使用者管理任務。 建置直接處理 Razor 工作的 Identity 元件在數個案例中是可行的,但 Microsoft 不建議這麽做亦不提供支援。
ASP.NET Core 抽象概念,例如 SignInManager<TUser> 和 UserManager<TUser>,在 Razor 元件中不受支援。 如需搭配使用 ASP.NET Core Identity 與 Blazor 的詳細資訊,請參閱 將 ASP.NET Core Identity 搭建到伺服器端 Blazor應用程式中。
注意
本文中的程式碼範例使用 nullable 參考型別 (NRT) 和 .NET 編譯器的 Null 狀態靜態分析,這些在 .NET 6 或更新版本的 ASP.NET Core 中都受到支援。 以 ASP.NET Core 5.0 或更早版本為目標時,請從本文的範例中移除 Null 型別指定 (?
)。
安全地維護敏感數據和認證
請勿在用戶端程式代碼中儲存應用程式秘密、連接字串、認證、密碼、個人標識碼 (PIN)、私人 .NET/C# 程式代碼或私鑰/令牌,這一律不安全。 Blazor用戶端程式代碼應該透過您控制的安全 Web API 來存取安全的服務和資料庫。
在測試/預備和生產環境中,伺服器端 Blazor 程序代碼和 Web API 應該使用安全驗證流程,以避免在專案程式代碼或組態檔內維護認證。 在本機開發測試之外,建議您避免使用環境變數來儲存敏感數據,因為環境變數不是最安全的方法。 針對本機開發測試, 建議使用秘密管理員工具 來保護敏感數據。 如需詳細資訊,請參閱以下資源:
針對客戶端和伺服器端本機開發和測試,請使用 秘密管理員工具來 保護敏感性認證。
Microsoft Azure 服務的受控識別
針對 Microsoft Azure 服務,我們建議使用 受控識別。 受控識別可以以安全的方式向 Azure 服務進行驗證,而無需在應用程式程式碼中儲存認證。 如需詳細資訊,請參閱以下資源:
- 什麼是 Azure 資源受控識別? (Microsoft Entra 說明文件)
- Azure 服務文件
防偽支援
Blazor 範本:
- 當在 AddRazorComponents 檔案中呼叫
Program
時,系統會自動新增防偽服務。 - 新增防偽中介軟體,藉由在 UseAntiforgery 檔案中的要求處理管線中呼叫
Program
,並要求端點有防偽保護,以減輕跨網站要求偽造 (CSRF/XSRF) 的威脅。 UseAntiforgery 被在 UseHttpsRedirection 之後呼叫。 如果存在對UseAntiforgery和UseAuthentication的呼叫,那麼必須在這些呼叫之後才呼叫UseAuthorization。
AntiforgeryToken 元件會將防偽權杖呈現為隱藏欄位,並且此元件會自動加入到表單 (EditForm) 的實例中。 如需詳細資訊,請參閱 ASP.NET Core Blazor 表單概觀。
AntiforgeryStateProvider 服務會提供與目前工作階段相關聯之防偽權杖的存取權。 插入服務並呼叫其 GetAntiforgeryToken() 方法來取得目前的 AntiforgeryRequestToken。 如需詳細資訊,請參閱 從 ASP.NET Core Blazor 應用程式呼叫 Web API。
Blazor 將請求權杖儲存在元件狀態中,這確保了即使在沒有請求存取權的情況下,互動式元件也能使用防偽權杖。
注意
當提交表單資料至伺服器,編碼為 、application/x-www-form-urlencoded
或 multipart/form-data
時,才需要執行偽造防範措施,因為只有這些是唯一有效的表單編碼類型。
如需詳細資訊,請參閱以下資源:
- 防止在 ASP.NET Core 中出現跨網站偽造要求 (XSRF/CSRF) 攻擊:這篇文章是關於此主題的主要 ASP.NET Core 文章,適用於伺服器端 Blazor Server、Blazor Web App 的伺服器專案,以及 Blazor 與 MVC/Razor 網頁的整合。
- ASP.NET Core 表單概觀:文章的防偽支援一節涉及表單防偽支援。
伺服器端 Blazor 驗證
為求安全,伺服器端 Blazor 應用程式的設定方式會與 ASP.NET Core 應用程式相同。 如需詳細資訊,請參閱 ASP.NET Core 安全性主題底下的文章。
只有在應用程式啟動時才會建立驗證內容,也就是應用程式第一次透過SignalR用戶端連線連線到 WebSocket 時。 驗證可以依據 cookie 或其他持有者權杖,但驗證會透過 SignalR 中樞並完全在 線路 內進行管理。 驗證上下文會在電路的存在期間受到維護。 應用程式會每隔 30 分鐘,定期重新驗證使用者的驗證狀態。
如果應用程式必須擷取使用者以進行自定義服務或回應使用者的更新,請參閱 ASP.NET Core 伺服器端和其他 Blazor Web App 安全性案例。
Blazor 不同於傳統伺服器轉譯的 Web 應用程式,這些應用程式會在瀏覽每個分頁時,使用 Cookie 提出新的 HTTP 要求。 瀏覽事件期間會檢查身份驗證。 不過,不涉及 Cookie。 只有在對伺服器提出 HTTP 要求時,才會傳送 Cookie,這不是使用者在 Blazor 應用程式中瀏覽時發生的情況。 瀏覽期間,會在 Blazor 線路內檢查使用者的驗證狀態,您可以使用 RevalidatingAuthenticationStateProvider
抽象隨時在伺服器上更新。
重要
不建議在瀏覽期間實作自訂 NavigationManager
來實現驗證確認。 如果應用程式必須在瀏覽期間執行自訂驗證狀態邏輯,請使用自訂 AuthenticationStateProvider
。
注意
本文中的程式碼範例使用 nullable 參考型別 (NRT) 和 .NET 編譯器的 Null 狀態靜態分析,這些在 .NET 6 或更新版本的 ASP.NET Core 中都受到支援。 以 ASP.NET Core 5.0 或更早版本為目標時,請從本文的範例中移除 Null 型別指定 (?
)。
內建或自訂 AuthenticationStateProvider 服務會從 ASP.NET Core 的 HttpContext.User 那邊取得驗證狀態資料。 這就是驗證狀態與現有 ASP.NET Core 驗證機制之間的整合方式。
如需伺服器端驗證的詳細資訊,請參閱 ASP.NET 核心 Blazor 驗證和授權。
共用狀態
伺服器端 Blazor 應用程式位於伺服器記憶體中,且多個應用程式工作階段會裝載在相同的處理程序內。 針對每個應用程式工作階段,Blazor 會啟動具有其本身相依性插入容器範圍的線路,因此每個 Blazor 工作階段的範圍服務都是唯一的。
警告
除非極為小心,否則不建議應用程式在同一伺服器上使用單例服務來共用狀態,因為這可能會造成安全性弱點,例如跨線路洩漏使用者的狀態資訊。
如果應用程式是特別設計的,您可以在 Blazor 應用程式中使用具狀態的單例服務。 例如,使用單例記憶體快取是可接受的,因為記憶體快取需要鍵值才能存取指定的項目。 假設使用者無法控制與快取搭配使用的快取索引鍵,則儲存在快取中的狀態不會跨線路洩漏。
如需狀態管理的一般指導,請參閱 ASP.NET Core Blazor 狀態管理。
敏感數據和認證的伺服器端安全性
在測試/預備和生產環境中,伺服器端 Blazor 程序代碼和 Web API 應該使用安全驗證流程,以避免在專案程式代碼或組態檔內維護認證。 在本機開發測試之外,建議您避免使用環境變數來儲存敏感數據,因為環境變數不是最安全的方法。 針對本機開發測試, 建議使用秘密管理員工具 來保護敏感數據。 如需詳細資訊,請參閱以下資源:
針對客戶端和伺服器端本機開發和測試,請使用 秘密管理員工具來 保護敏感性認證。
專案範本
遵循 Blazor 中的指引,建立新的伺服器端 Blazor 應用程式。
在選擇伺服器端應用程式範本並設定專案之後,請在 [驗證類型] 底下選取應用程式的驗證:
- 無 (預設值):無驗證。
- 個別帳戶:使用者帳戶會使用 ASP.NET Core Identity 儲存在應用程式內。
- 無 (預設值):無驗證。
- 個別帳戶:使用者帳戶會使用 ASP.NET Core Identity 儲存在應用程式內。
- Microsoft身分識別平臺:如需詳細資訊,請參閱 ASP.NET Core Blazor 驗證和授權。
- Windows:使用 Windows 驗證。
Blazor Identity UI (個人帳戶)
當您選擇 [個別帳戶] 的驗證選項時,Blazor 支援生成完整的以 Blazor 為基礎的 Identity UI。
Blazor Web App 範本會為 SQL Server 資料庫建構 Identity 程式碼。 命令列版本會使用 SQLite,並包含 Identity 的 SQLite 資料庫。
範本:
- 支援互動式伺服器端渲染 (互動式 SSR) 及含經驗證使用者的用戶端渲染 (CSR) 場景。
- 新增 IdentityRazor 例行驗證工作的元件和相關邏輯,例如:登入和登出的使用者。這些 Identity 元件也支援進階 Identity 功能,例如使用第三方應用程式進行帳戶確認和密碼復原,還有多重要素驗證 。 請注意 Identity 元件本身暫不支持互動功能。
- 新增 Identity 相關的套件和相依性。
- 引用 Identity 包中的
_Imports.razor
套件。 - 建立自訂使用者 Identity 類別 (
ApplicationUser
)。 - 建立並註冊 EF Core 資料庫上下文 (
ApplicationDbContext
)。 - 設定內建 Identity 端點的路由。
- 包含 Identity 驗證和商務邏輯。
若要檢查
當您選擇互動式 WebAssembly 或互動式自動轉譯模式時,伺服器會處理所有驗證和授權要求,而 Identity 元件會在 Blazor Web App 的主要專案中透過靜態方式,呈現在伺服器上。
架構會在伺服器和用戶端 (AuthenticationStateProvider) 專案中提供自訂 .Client
,以將使用者的驗證狀態流向瀏覽器。 伺服器專案會呼叫 AddAuthenticationStateSerialization
,而用戶端專案會呼叫 AddAuthenticationStateDeserialization
。 在伺服器上進行驗證,而不是在用戶端,允許應用程式在預渲染期間,以及在初始化 .NET WebAssembly 執行階段之前存取驗證狀態。 自訂 AuthenticationStateProvider 實作會使用保存元件狀態服務 (PersistentComponentState) 將驗證狀態序列化為 HTML 註解,然後從 WebAssembly 讀取它以建立新的 AuthenticationState 執行個體。 如需詳細資訊,請參閱在 Blazor Web App 中管理驗證狀態這個章節。
僅限於互動式伺服器解決方案,IdentityRevalidatingAuthenticationStateProvider
(參考來源) 是一個伺服器端的 AuthenticationStateProvider,當互動式線路連接時,每隔 30 分鐘會重新驗證已連線使用者的安全性戳記。
當您選擇互動式 WebAssembly 或互動式自動轉譯模式時,伺服器會處理所有驗證和授權要求,而 Identity 元件會在 Blazor Web App 的主要專案中透過靜態方式,呈現在伺服器上。 專案範本包括 PersistentAuthenticationStateProvider
專案中的 ,以同步伺服器與瀏覽器間的使用者驗證狀態。 類別是 AuthenticationStateProvider 的自訂實作。 提供者會使用保存元件狀態服務 (PersistentComponentState),預先轉譯驗證狀態,並將其保存至頁面。
在 Blazor Web App 的主要專案中,驗證狀態供應器名為 IdentityRevalidatingAuthenticationStateProvider
(參考來源)(僅限伺服器互動功能解決方案)或 PersistingRevalidatingAuthenticationStateProvider
(參考來源)(WebAssembly 或自動互動功能解決方案)。
Blazor Identity 取決於 DbContext 執行個體未由處理站建立,這是刻意的,因為 DbContext 足以讓專案範本的 Identity 元件以靜態方式轉譯,而不用支援互動功能。
如需在針對 Identity 元件強制執行靜態 SSR 的同時,全域互動轉譯模式如何套用至非 Identity 元件的描述,請參閱 ASP.NET Core Blazor 轉譯模式。
如需保存預先轉譯狀態的詳細資訊,請參閱預先轉譯 ASP.NET Core Razor 元件。
注意
.NET 參考文件的連結通常會開啟存放庫的預設分支,這是代表下一版 .NET 的當前開發內容。 若要為特定版本選取標籤,請使用 切換分支或標籤 下拉式清單。 如需詳細資訊,請參閱如何選取 ASP.NET Core 原始程式碼 (dotnet/AspNetCore.Docs #26205) 的版本標籤。
在 Blazor Web App 中管理驗證狀態
本章節適用於 Blazor Web App採用以下幾點的:
- 個人帳戶
- 客戶端渲染 (CSR,基於 WebAssembly 的互動式功能)。
用戶端驗證狀態供應器僅在 Blazor 內使用,不會與 ASP.NET Core 驗證系統整合。 在預先轉譯期間,Blazor 遵守頁面上定義的中繼資料,並且使用 ASP.NET Core 驗證系統來判斷使用者是否已驗證。 當使用者從一個頁面瀏覽到另一個頁面時,會使用用戶端驗證提供者。 當使用者重新整理頁面 (完整頁面重新載入) 時,用戶端驗證狀態供應器不會參與伺服器上的驗證決策。 由於伺服器不會保存使用者的狀態,因此維護用戶端的任何驗證狀態都會遺失。
若要解決此問題,最佳方法是在 ASP.NET Core 驗證系統中執行驗證。 用戶端驗證狀態供應器只會負責反映使用者的驗證狀態。 Blazor Web App 專案範本示範如何使用驗證狀態供應器來完成這項作業的範例,分述如下。
在伺服器專案的 Program
檔案中,呼叫 AddAuthenticationStateSerialization
,該函式會使用 AuthenticationStateAuthenticationStateProvider 來序列化伺服器端 傳回的 PersistentComponentState。
builder.Services.AddRazorComponents()
.AddInteractiveWebAssemblyComponents()
.AddAuthenticationStateSerialization();
這些 API 只會序列化伺服器端名稱和角色宣告,以在瀏覽器中存取。 若要包含所有宣告,請在伺服器端呼叫 SerializeAllClaims
時將 true
設定為 AddAuthenticationStateSerialization
。
builder.Services.AddRazorComponents()
.AddInteractiveWebAssemblyComponents()
.AddAuthenticationStateSerialization(
options => options.SerializeAllClaims = true);
在用戶端 (.Client
) 專案的 Program
檔案中,呼叫 AddAuthenticationStateDeserialization
,這會新增一個 AuthenticationStateProvider,其中使用 AuthenticationState 從伺服器反序列化AuthenticationStateData
,並由 永久元件狀態服務 (PersistentComponentState) 進行管理。 伺服器專案中應該有對 AddAuthenticationStateSerialization
的對應呼叫。
builder.Services.AddAuthorizationCore();
builder.Services.AddCascadingAuthenticationState();
builder.Services.AddAuthenticationStateDeserialization();
PersistingRevalidatingAuthenticationStateProvider
(參考來源) :針對 Blazor Web App 採用互動式伺服器端轉譯 (互動式 SSR) 和用戶端轉譯 (CSR)。 這是伺服器端 AuthenticationStateProvider,在每當連接互動線路時,每隔 30 分鐘重新驗證已連線使用者的安全性戳記。 也會使用永續性元件狀態服務,將驗證狀態流向用戶端,接著針對 CSR 的存留期加以修正。PersistingServerAuthenticationStateProvider
(參考來源):僅採用企業社會責任 (CSR) 的 Blazor Web App。 這是伺服器端 AuthenticationStateProvider,使用永續性元件狀態服務,將驗證狀態傳送到用戶端,然後在 CSR 的存續期內固定不變。PersistentAuthenticationStateProvider
(參考來源):採用企業社會責任的 Blazor Web App。 這是一個用戶端的 AuthenticationStateProvider,它藉由尋找在伺服器渲染時儲存在頁面中的資料來判斷使用者的驗證狀態。 此驗證狀態在 CSR 的生命週期中是固定不變的。 如果使用者需要登入或登出,則需要完整頁面重新載入。 這僅會提供使用者名稱和電子郵件以供顯示之用。 不包含用來在後續要求中對伺服器進行驗證的權杖,這需要由包含在對伺服器的 cookie 要求中的HttpClient
來個別處理。
注意
.NET 參考文件的連結通常會開啟存放庫的預設分支,這是代表下一版 .NET 的當前開發內容。 若要為特定版本選取標籤,請使用 切換分支或標籤 下拉式清單。 如需詳細資訊,請參閱如何選取 ASP.NET Core 原始程式碼 (dotnet/AspNetCore.Docs #26205) 的版本標籤。
支架Identity
如需將 Identity 搭建至伺服器端 Blazor 應用程式的詳細資訊,請參閱在 ASP.NET Core 專案中搭建 Identity。
來自外部提供者的其他聲明和憑證
若要儲存來自外部提供者的其他宣告,請參閱在 ASP.NET Core 中保存來自外部提供者的其他宣告和權杖。
Linux 上的 Azure App Service 搭配 Identity 伺服器
請在部署 Linux 上的 Azure App Service 與 Identity 伺服器時明確指定簽發者。 如需詳細資訊,請參閱使用 Identity 來保護 SPA 的 Web API 後端。
將 AuthenticationStateProvider
插入限於元件的服務中
請不要嘗試在自訂範圍內解析 AuthenticationStateProvider,因為其會導致為未正確初始化的 AuthenticationStateProvider 建立新執行個體。
若要存取範圍為元件之服務內的 AuthenticationStateProvider,請將 AuthenticationStateProvider 插入元件,並將它傳遞至服務做為參數。 此方法確保針對每個使用者應用程式實例使用初始化後的正確AuthenticationStateProvider實例。
ExampleService.cs
:
public class ExampleService
{
public async Task<string> ExampleMethod(AuthenticationStateProvider authStateProvider)
{
var authState = await authStateProvider.GetAuthenticationStateAsync();
var user = authState.User;
if (user.Identity is not null && user.Identity.IsAuthenticated)
{
return $"{user.Identity.Name} is authenticated.";
}
else
{
return "The user is NOT authenticated.";
}
}
}
將服務註冊為有範圍的。 在伺服器端 Blazor 應用程式中,限定範圍服務的存留期等於用戶端連線線路的持續時間。
在 Program
檔案中:
builder.Services.AddScoped<ExampleService>();
在 Startup.ConfigureServices
的 Startup.cs
中:
services.AddScoped<ExampleService>();
在下列 InjectAuthStateProvider
元件中:
- 元件會繼承 OwningComponentBase。
- 插入 AuthenticationStateProvider 並傳遞至
ExampleService.ExampleMethod
。 -
ExampleService
使用 OwningComponentBase.ScopedServices 和 GetRequiredService 來解決,這會傳回使用者線路存續期間內存在的正確、初始化的ExampleService
執行個體。
InjectAuthStateProvider.razor
:
@page "/inject-auth-state-provider"
@inherits OwningComponentBase
@inject AuthenticationStateProvider AuthenticationStateProvider
<h1>Inject <code>AuthenticationStateProvider</code> Example</h1>
<p>@message</p>
@code {
private string? message;
private ExampleService? ExampleService { get; set; }
protected override async Task OnInitializedAsync()
{
ExampleService = ScopedServices.GetRequiredService<ExampleService>();
message = await ExampleService.ExampleMethod(AuthenticationStateProvider);
}
}
@page "/inject-auth-state-provider"
@inject AuthenticationStateProvider AuthenticationStateProvider
@inherits OwningComponentBase
<h1>Inject <code>AuthenticationStateProvider</code> Example</h1>
<p>@message</p>
@code {
private string? message;
private ExampleService? ExampleService { get; set; }
protected override async Task OnInitializedAsync()
{
ExampleService = ScopedServices.GetRequiredService<ExampleService>();
message = await ExampleService.ExampleMethod(AuthenticationStateProvider);
}
}
如需詳細資訊,請參閱 OwningComponentBase中 Blazor 的相關指引。
使用自訂 AuthenticationStateProvider
預先轉譯時,會顯示未經授權的內容。
若要避免在使用自訂AuthorizeView
進行預先轉譯時顯示未經授權的內容,例如AuthenticationStateProvider
元件中的內容,請採用以下其中一種方法:
為自訂 IHostEnvironmentAuthenticationStateProvider 實作 AuthenticationStateProvider 以支援預渲染:如需 IHostEnvironmentAuthenticationStateProvider 的範例實作,請參閱 Blazor 架構中的 ServerAuthenticationStateProvider 實作。
注意
.NET 參考文件的連結通常會開啟存放庫的預設分支,這是代表下一版 .NET 的當前開發內容。 若要為特定版本選取標籤,請使用 切換分支或標籤 下拉式清單。 如需詳細資訊,請參閱如何選取 ASP.NET Core 原始程式碼 (dotnet/AspNetCore.Docs #26205) 的版本標籤。
停用預先轉譯:設定或指定轉譯模式,將
prerender
參數設置為false
,置於應用程式元件階層中根元件以外的最高階元件。注意
不支援讓根元件成為互動式,例如
App
元件。 因此,App
元件無法直接停用預先轉譯。針對以 Blazor Web App 專案範本為基礎的應用程式,通常會停用預先轉譯,在
Routes
元件 (App
) 中使用Components/App.razor
元件時:<Routes @rendermode="new InteractiveServerRenderMode(prerender: false)" />
此外,停用
HeadOutlet
元件的預先轉譯:<HeadOutlet @rendermode="new InteractiveServerRenderMode(prerender: false)" />
您也可以選擇性地控制套用至
Routes
元件執行個體的渲染模式。 如需範例,請參閱 ASP.NET Core Blazor 轉譯模式。
關閉預渲染:開啟
檔案,並將 的 的屬性變更為 : <component type="typeof(App)" render-mode="Server" />
- 在應用程式啟動前驗證伺服器上的使用者:若要採用這種方法,應用程式必須以 Identity 型登入頁面或檢視回應使用者的初始要求,並防止對 Blazor 端點的任何要求,直到其驗證完畢為止。 如需詳細資訊,請參閱使用受授權保護的使用者資料建立 ASP.NET Core 應用程式。 驗證之後,只有在使用者真正未經授權檢視內容時,才會顯示預先轉譯 Razor 元件中未經授權的內容。
使用者狀態管理
儘管名稱中有 "state" 這個字,但 AuthenticationStateProvider 不是用於儲存「一般使用者狀態」。 AuthenticationStateProvider 只會指出使用者對應用程式的驗證狀態、其是否登入應用程式,以及其以什麼身分登入。
驗證會使用與 Identity Pages 和 MVC 應用程式相同的 ASP.NET Core Razor 驗證。 針對 ASP.NET Core Identity 儲存的使用者狀態會流向 Blazor,而無需將額外的程式碼新增至應用程式。 請遵循 ASP.NET Core Identity 文章和教學課程中的指引,讓 Identity 功能在應用程式的 Blazor 組件中生效。
如需 ASP.NET Core Identity 以外的一般狀態管理指引,請參閱 ASP.NET Core Blazor 狀態管理。
其他安全性抽象
有兩個額外的抽象會參與管理驗證狀態:
ServerAuthenticationStateProvider (參考來源):AuthenticationStateProvider 是由 Blazor 架構用來從伺服器取得驗證狀態的工具。
RevalidatingServerAuthenticationStateProvider (參考來源):AuthenticationStateProvider 服務的基底類別,而 Blazor 架構會使用這些服務,從主機環境接收驗證狀態,並定期重新驗證。
預設 30 分鐘的重新驗證間隔可在
RevalidatingIdentityAuthenticationStateProvider
(Areas/Identity/RevalidatingIdentityAuthenticationStateProvider.cs
) 中進行調整。 下列範例會將間隔縮短為 20 分鐘:protected override TimeSpan RevalidationInterval => TimeSpan.FromMinutes(20);
注意
.NET 參考文件的連結通常會開啟存放庫的預設分支,這是代表下一版 .NET 的當前開發內容。 若要為特定版本選取標籤,請使用 切換分支或標籤 下拉式清單。 如需詳細資訊,請參閱如何選取 ASP.NET Core 原始程式碼 (dotnet/AspNetCore.Docs #26205) 的版本標籤。
登出時的驗證狀態管理
伺服器端 Blazor 會在電路存活期內保存使用者驗證狀態,包括跨瀏覽器標籤頁。 當使用者在某一個標籤頁上登出時,若要在所有瀏覽器標籤頁中主動將使用者登出,您必須使用具有簡短RevalidationInterval的RevalidatingServerAuthenticationStateProvider (參考來源) 來實施。
注意
.NET 參考文件的連結通常會開啟存放庫的預設分支,這是代表下一版 .NET 的當前開發內容。 若要為特定版本選取標籤,請使用 切換分支或標籤 下拉式清單。 如需詳細資訊,請參閱如何選取 ASP.NET Core 原始程式碼 (dotnet/AspNetCore.Docs #26205) 的版本標籤。
暫時重新導向 URL 有效期間
本章節適用於 Blazor Web App。
使用 RazorComponentsServiceOptions.TemporaryRedirectionUrlValidityDuration 選項來取得或設定由 Blazor 伺服器端轉譯發出的暫時重新導向 URL 的 ASP.NET Core 資料保護有效性的存留期。 這些只是暫時使用,因此存留期只要足夠讓用戶端接收 URL 並開始瀏覽至該 URL 即可。 不過,時間也應該足夠長,以應對跨伺服器的時鐘偏差。 預設值為五分鐘。
在下列範例中,該值會延長至七分鐘:
builder.Services.AddRazorComponents(options =>
options.TemporaryRedirectionUrlValidityDuration =
TimeSpan.FromMinutes(7));
用戶端 Blazor 驗證
在用戶端 Blazor 應用程式中,用戶端驗證檢查可以被略過,因為使用者可以修改所有用戶端端程式碼。 這同樣也適用於所有的用戶端端的應用程式技術,包括 JavaScript SPA 架構或任何作業系統的原生應用程式。
新增下列項目:
Microsoft.AspNetCore.Components.Authorization
NuGet 套件的參考包。應用程式 Microsoft.AspNetCore.Components.Authorization 檔案的
_Imports.razor
命名空間。
若想處理驗證,請使用內建或自訂的 AuthenticationStateProvider 服務。
如需客戶端驗證的詳細資訊,請參閱 安全 ASP.NET Core Blazor WebAssembly的說明。
使用互動式自動渲染保護 Blazor Web App區塊中的數據
當 Blazor Web App 採用伺服器端渲染(SSR)和用戶端渲染(CSR)來處理元件或整個應用程式,並指定 互動式自動渲染模式時,會在 兩個地方套用存取元件和數據的授權。 元件會藉由元件定義檔 (@attribute [Authorize]
) 中的授權屬性,限制在伺服器上轉譯時本身的存取權(以及它取得的任何數據)。 在用戶端上轉譯元件時,會透過從用戶端呼叫的伺服器 Web API 端點來限制對資料的存取。 保護這兩個位置的數據存取時,必須小心,以避免數據存取不當。
請考慮下列案例,其中元件會顯示安全的天氣數據。 您可以在執行中的範例應用程式中檢查並示範下列範例,其中 BlazorWebAppEntra
/BlazorWebAppEntraBff
範例(.NET 9 或更新版本)或 BlazorWebAppOidc
範例 GitHub 存放庫中的 Blazor 範例 (dotnet/blazor-samples
) (如何下載)。
用戶端項目會維護 WeatherForecast
類別來保存天氣資料:
public sealed class WeatherForecast(DateOnly date, int temperatureC, string summary)
{
public DateOnly Date { get; set; } = date;
public int TemperatureC { get; set; } = temperatureC;
public string? Summary { get; set; } = summary;
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
}
用戶端項目的 IWeatherForecaster
介面會定義取得天氣數據的 GetWeatherForecastAsync
方法:
public interface IWeatherForecaster
{
Task<IEnumerable<WeatherForecast>> GetWeatherForecastAsync();
}
用戶端項目的 ClientWeatherForecaster
服務會實作 IWeatherForecaster
。
GetWeatherForecastAsync
方法會在伺服器專案中針對天氣數據,呼叫位於 /weather-forecast
端點的 web API。
internal sealed class ClientWeatherForecaster(HttpClient httpClient)
: IWeatherForecaster
{
public async Task<IEnumerable<WeatherForecast>> GetWeatherForecastAsync() =>
await httpClient.GetFromJsonAsync<WeatherForecast[]>("/weather-forecast") ??
throw new IOException("No weather forecast!");
}
客戶專案維持下列 Weather
元件:
- 使用屬性
[Authorize]
強制執行授權。 - 當元件從伺服器上的靜態轉換成互動式 SSR 時,使用 持續性元件狀態服務 (PersistentComponentState) 來保存天氣預報數據。 如需詳細資訊,請參閱預先轉譯 ASP.NET Core Razor 元件。
@page "/weather"
@using Microsoft.AspNetCore.Authorization
@using BlazorWebAppEntra.Client.Weather
@attribute [Authorize]
@inject IWeatherForecaster WeatherForecaster
<PageTitle>Weather</PageTitle>
<h1>Weather</h1>
<p>This component demonstrates showing data.</p>
@if (Forecasts == null)
{
<p><em>Loading...</em></p>
}
else
{
<table class="table">
<thead>
<tr>
<th>Date</th>
<th aria-label="Temperature in Celsius">Temp. (C)</th>
<th aria-label="Temperature in Fahrenheit">Temp. (F)</th>
<th>Summary</th>
</tr>
</thead>
<tbody>
@foreach (var forecast in Forecasts)
{
<tr>
<td>@forecast.Date.ToShortDateString()</td>
<td>@forecast.TemperatureC</td>
<td>@forecast.TemperatureF</td>
<td>@forecast.Summary</td>
</tr>
}
</tbody>
</table>
}
@code {
[SupplyParameterFromPersistentComponentState]
public IEnumerable<WeatherForecast>? Forecasts { get; set; }
protected override async Task OnInitializedAsync()
{
Forecasts ??= await WeatherForecaster.GetWeatherForecastAsync();
}
}
@page "/weather"
@using Microsoft.AspNetCore.Authorization
@using BlazorWebAppEntra.Client.Weather
@attribute [Authorize]
@implements IDisposable
@inject PersistentComponentState ApplicationState
@inject IWeatherForecaster WeatherForecaster
<PageTitle>Weather</PageTitle>
<h1>Weather</h1>
<p>This component demonstrates showing data.</p>
@if (forecasts == null)
{
<p><em>Loading...</em></p>
}
else
{
<table class="table">
<thead>
<tr>
<th>Date</th>
<th aria-label="Temperature in Celsius">Temp. (C)</th>
<th aria-label="Temperature in Fahrenheit">Temp. (F)</th>
<th>Summary</th>
</tr>
</thead>
<tbody>
@foreach (var forecast in forecasts)
{
<tr>
<td>@forecast.Date.ToShortDateString()</td>
<td>@forecast.TemperatureC</td>
<td>@forecast.TemperatureF</td>
<td>@forecast.Summary</td>
</tr>
}
</tbody>
</table>
}
@code {
private IEnumerable<WeatherForecast>? forecasts;
private PersistingComponentStateSubscription persistingSubscription;
protected override async Task OnInitializedAsync()
{
if (!ApplicationState.TryTakeFromJson<IEnumerable<WeatherForecast>>(
nameof(forecasts), out var restoredData))
{
forecasts = await WeatherForecaster.GetWeatherForecastAsync();
}
else
{
forecasts = restoredData!;
}
// Call at the end to avoid a potential race condition at app shutdown
persistingSubscription = ApplicationState.RegisterOnPersisting(PersistData);
}
private Task PersistData()
{
ApplicationState.PersistAsJson(nameof(forecasts), forecasts);
return Task.CompletedTask;
}
void IDisposable.Dispose() => persistingSubscription.Dispose();
}
伺服器專案會將 IWeatherForecaster
實作為 ServerWeatherForecaster
,其會透過其 GetWeatherForecastAsync
方法產生並傳回模擬天氣數據:
public class ServerWeatherForecaster() : IWeatherForecaster
{
public readonly string[] summaries =
[
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot",
"Sweltering", "Scorching"
];
public async Task<IEnumerable<WeatherForecast>> GetWeatherForecastAsync()
{
// Simulate asynchronous loading to demonstrate streaming rendering
await Task.Delay(500);
return Enumerable.Range(1, 5).Select(index =>
new WeatherForecast
(
DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
Random.Shared.Next(-20, 55),
summaries[Random.Shared.Next(summaries.Length)]
))
.ToArray();
}
}
伺服器專案會維護客戶端天氣資料呼叫的安全 Web API 端點:
app.MapGet("/weather-forecast", (
[FromServices] IWeatherForecaster WeatherForecaster) =>
{
return WeatherForecaster.GetWeatherForecastAsync();
}).RequireAuthorization();
使用上述方法時,有兩個系統可為使用者提供安全的天氣數據:
- 當伺服器
Weather
轉譯 元件時,會直接使用ServerWeatherForecaster
服務的GetWeatherForecastAsync
方法來取得天氣數據。 數據的安全性是由元件的[Authorize]
屬性強制執行。 總而言之,天氣數據的安全性是由元件強制執行。 - 在用戶端
Weather
轉譯 元件時,ClientWeatherForecaster
服務會用來對套用/weather-forecast
擴充方法的安全 RequireAuthorization 端點進行 Web API 呼叫。 如果使用者有權存取天氣資料,端點會使用ServerWeatherForecaster
服務來呼叫GetWeatherForecastAsync
。 數據會傳回給用戶端。 總而言之,伺服器應用程式的 Web API 端點會強制執行天氣數據的安全性。
當 Web API 的安全性需求符合元件的安全性需求時,上述方法會正常運作。 例如,相同的授權原則可以同時套用至 Web API 端點和元件。
複雜的案例需要額外的規劃和實作。 例如,具有不同訪問許可權的多個呼叫端的伺服器 Web API 需要更複雜的授權原則、一或多個其他原則,或具有不同存取需求的其他端點。
當您將安全性建置至採用互動式自動轉譯的應用程式時,請注意,針對伺服器的 Web API 端點實作所實作的安全性不會保護伺服器上轉譯元件時所使用的伺服器服務實作,並透過服務存取數據。 仔細權衡在 SSR 期間存取伺服器上的數據與在 CSR 期間存取用戶端 Web API 要求上的數據之間的差異。 策略性地套用安全性,以避免不當存取數據。
Blazor 範例 GitHub 存放庫(dotnet/blazor-samples
)(如何下載)中的範例,示範本節所述的方法:
BlazorWebAppOidc
BlazorWebAppOidcBff
BlazorWebAppEntra
BlazorWebAppEntraBff
AuthenticationStateProvider
服務
AuthenticationStateProvider 是 AuthorizeView 元件和串聯驗證服務用來取得使用者驗證狀態的基礎服務。
AuthenticationStateProvider 是 AuthorizeView 元件與 CascadingAuthenticationState 元件用來取得使用者驗證狀態的基礎服務。
您通常不會直接使用 AuthenticationStateProvider。 請使用本文稍後所述的 AuthorizeView
元件或 Task<AuthenticationState>
方法。 使用 AuthenticationStateProvider 的主要缺點,在於系統不會在基礎驗證狀態資料變更時自動通知該元件。
若想執行自訂 AuthenticationStateProvider,請參閱 ASP.NET Core Blazor 驗證狀態,內容包含執行使用者驗證狀態的變更通知指南。
取得使用者的權利主體資料
AuthenticationStateProvider 服務可以提供目前使用者的 ClaimsPrincipal 資料,如下列範例所示。
ClaimsPrincipalData.razor
:
@page "/claims-principal-data"
@using System.Security.Claims
@inject AuthenticationStateProvider AuthenticationStateProvider
<h1>ClaimsPrincipal Data</h1>
<button @onclick="GetClaimsPrincipalData">Get ClaimsPrincipal Data</button>
<p>@authMessage</p>
@if (claims.Any())
{
<ul>
@foreach (var claim in claims)
{
<li>@claim.Type: @claim.Value</li>
}
</ul>
}
<p>@surname</p>
@code {
private string? authMessage;
private string? surname;
private IEnumerable<Claim> claims = Enumerable.Empty<Claim>();
private async Task GetClaimsPrincipalData()
{
var authState = await AuthenticationStateProvider
.GetAuthenticationStateAsync();
var user = authState.User;
if (user.Identity is not null && user.Identity.IsAuthenticated)
{
authMessage = $"{user.Identity.Name} is authenticated.";
claims = user.Claims;
surname = user.FindFirst(c => c.Type == ClaimTypes.Surname)?.Value;
}
else
{
authMessage = "The user is NOT authenticated.";
}
}
}
在前述範例中:
-
ClaimsPrincipal.Claims 會傳回使用者宣告 (
claims
) 以顯示在 UI 中。 - 取得使用者姓氏 (
surname
) 的行會使用述詞來呼叫 ClaimsPrincipal.FindAll,以篩選使用者的宣告。
@page "/claims-principal-data"
@using System.Security.Claims
@inject AuthenticationStateProvider AuthenticationStateProvider
<h1>ClaimsPrincipal Data</h1>
<button @onclick="GetClaimsPrincipalData">Get ClaimsPrincipal Data</button>
<p>@authMessage</p>
@if (claims.Any())
{
<ul>
@foreach (var claim in claims)
{
<li>@claim.Type: @claim.Value</li>
}
</ul>
}
<p>@surname</p>
@code {
private string? authMessage;
private string? surname;
private IEnumerable<Claim> claims = Enumerable.Empty<Claim>();
private async Task GetClaimsPrincipalData()
{
var authState = await AuthenticationStateProvider
.GetAuthenticationStateAsync();
var user = authState.User;
if (user.Identity is not null && user.Identity.IsAuthenticated)
{
authMessage = $"{user.Identity.Name} is authenticated.";
claims = user.Claims;
surname = user.FindFirst(c => c.Type == ClaimTypes.Surname)?.Value;
}
else
{
authMessage = "The user is NOT authenticated.";
}
}
}
如果 user.Identity.IsAuthenticated
為 true
,因使用者為 ClaimsPrincipal,便可以列舉權利要求,並評估角色中的成員資格。
如需相依性插入 (DI) 和服務的詳細資訊,請參閱 ASP.NET Core Blazor 相依性插入和 ASP.NET Core 中的相依性插入。 如需索取關於如何執行自訂 AuthenticationStateProvider 的詳細資訊,請參閱 ASP.NET Core Blazor 驗證狀態說明。
將驗證狀態公開為階層式參數
如果程序性邏輯需要驗證狀態資料(例如在執行由使用者觸發的動作時),請透過定義一個級聯參數,其類型為Task<
AuthenticationState>
,來取得驗證狀態資料,如下列範例所示。
CascadeAuthState.razor
:
@page "/cascade-auth-state"
<h1>Cascade Auth State</h1>
<p>@authMessage</p>
@code {
private string authMessage = "The user is NOT authenticated.";
[CascadingParameter]
private Task<AuthenticationState>? authenticationState { get; set; }
protected override async Task OnInitializedAsync()
{
if (authenticationState is not null)
{
var authState = await authenticationState;
var user = authState?.User;
if (user?.Identity is not null && user.Identity.IsAuthenticated)
{
authMessage = $"{user.Identity.Name} is authenticated.";
}
}
}
}
@page "/cascade-auth-state"
<h1>Cascade Auth State</h1>
<p>@authMessage</p>
@code {
private string authMessage = "The user is NOT authenticated.";
[CascadingParameter]
private Task<AuthenticationState>? authenticationState { get; set; }
protected override async Task OnInitializedAsync()
{
if (authenticationState is not null)
{
var authState = await authenticationState;
var user = authState?.User;
if (user?.Identity is not null && user.Identity.IsAuthenticated)
{
authMessage = $"{user.Identity.Name} is authenticated.";
}
}
}
}
如果 user.Identity.IsAuthenticated
是 true
,則可以列舉權限,並評估角色中的成員資格。
使用 Task<
AuthenticationState>
串聯參數 及串聯驗證狀態服務設定 AuthorizeRouteView。
當您從其中一個已啟用驗證的 Blazor 專案範本建立 Blazor 應用程式時,此應用程式會包含上述範例中顯示的 AuthorizeRouteView 以及對 AddCascadingAuthenticationState 的呼叫。 用戶端 Blazor 應用程式也包含所需的服務註冊。 在〈使用 Router
元件自訂未經授權內容〉部分中,會顯示其他資訊。
<Router ...>
<Found ...>
<AuthorizeRouteView RouteData="routeData"
DefaultLayout="typeof(Layout.MainLayout)" />
...
</Found>
</Router>
在 Program
檔案中,註冊串聯驗證狀態服務:
builder.Services.AddCascadingAuthenticationState();
使用 Task<
和 AuthenticationState 元件設定 >
串聯參數。
當您從其中一個已啟用驗證的 Blazor 專案範本建立 Blazor 應用程式時,此應用程式會包含上述範例中顯示的 AuthorizeRouteView 和 CascadingAuthenticationState 元件。 用戶端 Blazor 應用程式也包含所需的服務註冊。 在〈使用 Router
元件自訂未經授權內容〉部分中,會顯示其他資訊。
<CascadingAuthenticationState>
<Router ...>
<Found ...>
<AuthorizeRouteView RouteData="routeData"
DefaultLayout="typeof(MainLayout)" />
...
</Found>
</Router>
</CascadingAuthenticationState>
注意
隨著 ASP.NET Core 5.0.1 的發行以及在任何其他 5.x 版中,Router
元件會包含設定為 PreferExactMatches
的 @true
參數。 如需詳細資訊,請參閱從 ASP.NET Core 3.1 移轉至 5.0。
在用戶端 Blazor 應用程式中,將授權服務新增至 Program
檔案:
builder.Services.AddAuthorizationCore();
在用戶端 Blazor 應用程式中,將選項和授權服務新增至 Program
檔案:
builder.Services.AddOptions();
builder.Services.AddAuthorizationCore();
在伺服器端 Blazor 應用程式中,選項和授權的服務已經存在,因此不需要再採取進一步動作。
授權
在使用者被驗證之後,系統便會套用「授權」規則以控制使用者可以執行的動作。
存取權通常會依據下列情況來授與或拒絕:
- 使用者已通過驗證 (已登入)。
- 使用者屬於某個「角色」。
- 使用者擁有權限。
- 已滿足某個「原則」。
上述概念皆和 ASP.NET Core MVC 或 Razor Pages 應用程式中的概念相同。 如需 ASP.NET Core 安全性的詳細資訊,請參閱 ASP.NET Core 安全性與Identity下的文章。
AuthorizeView
元件
AuthorizeView 元件會根據使用者是否獲得授權來選擇性地顯示 UI 內容。 當您只需要 向用戶顯示 數據,且不需要在程式邏輯中使用使用者的身分識別時,這個方法就很有用。
該元件會公開 context
類型的 AuthenticationState 變數 (@context
語法中的 Razor),您可以使用它來存取已登入使用者的相關資訊:
<AuthorizeView>
<p>Hello, @context.User.Identity?.Name!</p>
</AuthorizeView>
您也可以使用 Authorized 和 NotAuthorized 參數的組合提供不同的顯示內容,以便在使用者未獲授權時顯示。
<AuthorizeView>
<Authorized>
<p>Hello, @context.User.Identity?.Name!</p>
<p><button @onclick="HandleClick">Authorized Only Button</button></p>
</Authorized>
<NotAuthorized>
<p>You're not authorized.</p>
</NotAuthorized>
</AuthorizeView>
@code {
private void HandleClick() { ... }
}
AuthorizeView雖然元件會根據使用者的授權狀態控制元素的可見度,但它不會對事件處理程式本身強制執行安全性。 在上述範例中, HandleClick
方法只會與授權用戶可見的按鈕相關聯,但沒有任何方法可防止從其他地方叫用此方法。 若要確保方法層級安全性,請在處理程式本身或相關 API 中實作額外的授權邏輯。
Razor 的 Blazor Web App 元件在靜態伺服器端轉譯 (靜態 SSR) 期間授權失敗時,一律不會顯示 <NotAuthorized>
內容。 伺服器端 ASP.NET Core 管線會處理伺服器上的授權。 使用伺服器端技術來處理未經授權的要求。 如需詳細資訊,請參閱 ASP.NET Core Blazor 轉譯模式。
警告
與 AuthorizeView 相關聯的用戶端標記和方法僅在用戶端應用程式的 渲染介面 中受到保護,不可被檢視或執行。 為了保護用戶端端 Blazor 中授權的內容和安全方法,內容通常是由安全、授權的 Web API 呼叫提供給伺服器 API,且永遠不會儲存在應用程式中。 如需詳細資訊,請參閱 從 ASP.NET Core Blazor應用程式 呼叫 Web API 和 ASP.NET CoreBlazor WebAssembly 其他安全性案例。
Authorized 和 NotAuthorized 的內容可以包含任意項目,例如其他互動式元件。
授權情況 (例如控制 UI 選項或存取的角色或原則) 已涵蓋於授權一節。
如果未指定授權條件,AuthorizeView 會使用預設的原則:
- 已驗證 (已登入) 的使用者視為已授權。
- 未驗證 (已登出) 的使用者視為未授權。
AuthorizeView 元件可用於 NavMenu
元件 (Shared/NavMenu.razor
) 以顯示 NavLink
元件 (NavLink),但請注意,此方法只會從轉譯的輸出中移除清單項目。 這不會防止使用者瀏覽至元件。 在目的地元件中個別實作授權。
角色型和原則型授權
AuthorizeView 元件支援「角色型」或「原則型」授權。
針對角色型授權,請使用 Roles 參數。 在下例中,使用者必須具有 Admin
或 Superuser
角色宣告。
<AuthorizeView Roles="Admin, Superuser">
<p>You have an 'Admin' or 'Superuser' role claim.</p>
</AuthorizeView>
若要要求使用者同時具有 Admin
和 Superuser
角色宣告,請嵌套 AuthorizeView 元件:
<AuthorizeView Roles="Admin">
<p>User: @context.User</p>
<p>You have the 'Admin' role claim.</p>
<AuthorizeView Roles="Superuser" Context="innerContext">
<p>User: @innerContext.User</p>
<p>You have both 'Admin' and 'Superuser' role claims.</p>
</AuthorizeView>
</AuthorizeView>
上述程式碼會為內部 Context
元件建立 AuthorizeView,以防止 AuthenticationState 內容衝突。 在外部 AuthenticationState 中,AuthorizeView 內容會使用存取內容的標準方法 (@context.User
) 來存取。 內部 AuthorizeView 的內容會在具名的 innerContext
環境 (@innerContext.User
) 中存取。
如需詳細資訊,包括設定指引,請參閱 ASP.NET Core 中的角色型授權。
針對以原則為基礎的授權,請使用 Policy 參數搭配單一原則名稱:
<AuthorizeView Policy="Over21">
<p>You satisfy the 'Over21' policy.</p>
</AuthorizeView>
若要處理使用者應該滿足數個原則之一的情況,請建立原則,確認使用者符合其他原則。
若要處理使用者必須同時滿足數個原則的情況,請採取 下列其中一種 方法:
建立 AuthorizeView 的原則,確認使用者符合數個其他原則。
將政策嵌套在多個 AuthorizeView 元件中。
<AuthorizeView Policy="Over21"> <AuthorizeView Policy="LivesInCalifornia"> <p>You satisfy the 'Over21' and 'LivesInCalifornia' policies.</p> </AuthorizeView> </AuthorizeView>
宣告型授權是原則型授權中的一個特殊案例。 例如,您可以定義要求使用者具備特定宣稱的原則。 如需詳細資訊,請參閱 ASP.NET Core 中的原則型授權。
如果未指定 Roles 和 Policy,AuthorizeView 便會使用預設原則:
- 已驗證 (已登入) 的使用者視為已授權。
- 未驗證 (已登出) 的使用者視為未授權。
因為 .NET 字串比較會區分大小寫,所以匹配角色名稱與原則名稱也會區分大小寫。 例如,Admin
(大寫 A
) 不會被視為與 admin
(小寫 a
) 相同的角色。
Pascal 命名法通常用於角色和原則名稱(例如 BillingAdministrator
),但使用 Pascal 命名法並不是硬性規定。 允許不同的命名方式,例如駝峰式(camel case)、短橫式(kebab case)和底線式(snake case)。 在角色和原則名稱中使用空格不尋常,但架構允許。 例如,billing administrator
在 .NET 應用程式中雖是不尋常的角色或原則名稱格式,但是個有效的角色或原則名稱。
在非同步驗證期間所顯示的內容
Blazor 允許以「非同步」方式判斷驗證狀態。 此方法的主要案例是會向外部端點要求驗證的用戶端端 Blazor 應用程式。
在進行驗證期間,AuthorizeView 不會顯示任何內容。 若要在驗證進行時顯示內容,請將內容指派給 Authorizing 參數:
<AuthorizeView>
<Authorized>
<p>Hello, @context.User.Identity?.Name!</p>
</Authorized>
<Authorizing>
<p>You can only see this content while authentication is in progress.</p>
</Authorizing>
</AuthorizeView>
此方法通常不適用於伺服器端 Blazor 應用程式。 伺服器端 Blazor 應用程式在驗證狀態建立時,便能立即得知該狀態。 可以在應用程式的 Authorizing 元件中提供 AuthorizeView 內容,但該內容永遠不會顯示。
[Authorize]
屬性
[Authorize]
屬性 可在 Razor 元件中使用。
@page "/"
@attribute [Authorize]
You can only see this if you're signed in.
重要
僅在透過 [Authorize]
路由器抵達的 @page
元件上使用 Blazor。 授權僅會以路由的層面執行,且不適用於在頁面內渲染的子元件。 若要授權在頁面內顯示特定組件,請改為使用 AuthorizeView。
[Authorize]
屬性也支援角色型或原則型授權。 針對角色型授權,請使用 Roles 參數:
@page "/"
@attribute [Authorize(Roles = "Admin, Superuser")]
<p>You can only see this if you're in the 'Admin' or 'Superuser' role.</p>
針對原則型授權,請使用 Policy 參數:
@page "/"
@attribute [Authorize(Policy = "Over21")]
<p>You can only see this if you satisfy the 'Over21' policy.</p>
如果未指定 Roles 和 Policy,[Authorize]
便會使用預設原則:
- 已驗證 (已登入) 的使用者視為已授權。
- 未驗證 (已登出) 的使用者視為未授權。
當使用者未獲得授權,且應用程式未 使用 Router
元件自訂未經授權的內容時,架構會自動顯示下列後援訊息:
Not authorized.
資源授權
若要授權使用者使用資源,請將要求的路由資料傳遞至 Resource 的 AuthorizeRouteView 參數。
在要求路由的 Router.Found 內容中:
<AuthorizeRouteView Resource="routeData" RouteData="routeData"
DefaultLayout="typeof(MainLayout)" />
如需如何在程序邏輯中傳遞及使用授權狀態資料的詳細資訊,請參閱將驗證狀態公開為串聯參數一節。
當 AuthorizeRouteView 收到資源的路由資料時,授權原則可以存取 RouteData.PageType 和 RouteData.RouteValues 以讓自訂邏輯決定是否授權。
在以下範例中,根據下列邏輯,在 EditUser
中建立一個 AuthorizationOptions 原則,來設定應用程式的授權服務設定 (AddAuthorizationCore)。
- 判斷是否有索引鍵為
id
的路由值存在。 如果該索引鍵存在,路由值便會儲存到value
中。 - 在名為
id
的變數中,將value
儲存為字串,或設定空字串值 (string.Empty
)。 - 如果
id
不是空字串,且字串值的開頭為true
,則判定滿足原則 (傳回EMP
)。 否則,確認政策失敗 (傳回false
)。
在 Program
檔案中:
為 Microsoft.AspNetCore.Components 和 System.Linq 新增命名空間:
using Microsoft.AspNetCore.Components; using System.Linq;
新增原則:
options.AddPolicy("EditUser", policy => policy.RequireAssertion(context => { if (context.Resource is RouteData rd) { var routeValue = rd.RouteValues.TryGetValue("id", out var value); var id = Convert.ToString(value, System.Globalization.CultureInfo.InvariantCulture) ?? string.Empty; if (!string.IsNullOrEmpty(id)) { return id.StartsWith("EMP", StringComparison.InvariantCulture); } } return false; }) );
上述範例是過度簡化的授權原則,這麼做只是為了透過運作範例來示範概念。 如需如何建立和設定授權原則的詳細資訊,請參閱 ASP.NET Core 中的原則型授權。
在下列 EditUser
元件中,位於 /users/{id}/edit
的資源具有使用者識別碼 ({id}
) 的路由參數。 元件會使用上述 EditUser
授權原則來判斷 id
的路由值是否以 EMP
開頭。 如果 id
以 EMP
開頭,則該策略會成功運作,且獲得授權可存取元件。 如果 id
以 EMP
以外的值開頭,或如果 id
是空字串,則原則會失敗,且元件不會載入。
EditUser.razor
:
@page "/users/{id}/edit"
@using Microsoft.AspNetCore.Authorization
@attribute [Authorize(Policy = "EditUser")]
<h1>Edit User</h1>
<p>The "EditUser" policy is satisfied! <code>Id</code> starts with 'EMP'.</p>
@code {
[Parameter]
public string? Id { get; set; }
}
@page "/users/{id}/edit"
@using Microsoft.AspNetCore.Authorization
@attribute [Authorize(Policy = "EditUser")]
<h1>Edit User</h1>
<p>The "EditUser" policy is satisfied! <code>Id</code> starts with 'EMP'.</p>
@code {
[Parameter]
public string? Id { get; set; }
}
使用 Router
元件來自訂未經授權的內容
如有下列情況,Router 元件與 AuthorizeRouteView 元件可讓應用程式指定自訂內容:
- 使用者無法滿足套用至元件的
[Authorize]
條件。 系統會顯示<NotAuthorized>
元素的標記。[Authorize]
屬性在[Authorize]
屬性一節中介紹。 - 正在進行非同步授權,這通常表示正在進行驗證使用者的程序。 系統會顯示
<Authorizing>
元素的標記。
重要
顯示Blazor和<NotAuthorized>
內容的Blazor路由功能無法在靜態伺服器端轉譯(靜態 SSR)期間運行,因為請求處理完全由 ASP.NET Core 中介軟體管線負責,且針對未經授權或錯誤的請求,Razor 元件根本不會被轉譯。 使用伺服器端技術來處理靜態 SSR 期間未經授權的和不正確的要求。 如需詳細資訊,請參閱 ASP.NET Core Blazor 轉譯模式。
<Router ...>
<Found ...>
<AuthorizeRouteView ...>
<NotAuthorized>
...
</NotAuthorized>
<Authorizing>
...
</Authorizing>
</AuthorizeRouteView>
</Found>
</Router>
Authorized 和 NotAuthorized 的內容可以包含任意項目,例如其他互動式元件。
注意
上述內容要求在應用程式的 Program
檔案中註冊串聯驗證狀態服務:
builder.Services.AddCascadingAuthenticationState();
<CascadingAuthenticationState>
<Router ...>
<Found ...>
<AuthorizeRouteView ...>
<NotAuthorized>
...
</NotAuthorized>
<Authorizing>
...
</Authorizing>
</AuthorizeRouteView>
</Found>
</Router>
</CascadingAuthenticationState>
NotFound、Authorized 及 NotAuthorized 的內容可以包含任意項目,例如其他互動式元件。
如果未指定 NotAuthorized 內容,AuthorizeRouteView 會使用下列後援訊息:
Not authorized.
從已啟用驗證的 Blazor WebAssembly 專案範本建立的應用程式會包含一個 RedirectToLogin
元件,該元件位於 <NotAuthorized>
元件的 Router 內容中。 未驗證使用者時 (context.User.Identity?.IsAuthenticated != true
),RedirectToLogin
元件會將瀏覽器重新導向至 authentication/login
端點以進行驗證。 使用者會在向識別提供者進行驗證之後,傳回至要求的URL。
程序性邏輯
如果作為程序性邏輯的一部分,應用程式必須檢查授權規則,請使用 Task<
AuthenticationState>
類型的階層式參數來取得使用者的 ClaimsPrincipal。
Task<
AuthenticationState
>
可以與其他服務 (例如 IAuthorizationService
) 結合來評估原則。
在以下範例中:
-
user.Identity.IsAuthenticated
會針對已驗證 (已登入) 的使用者執行程式碼。 -
user.IsInRole("admin")
會針對 「管理員」角色中的使用者執行程式碼。 -
(await AuthorizationService.AuthorizeAsync(user, "content-editor")).Succeeded
會針對滿足「內容編輯器」原則的使用者執行程式碼。
從專案範本建立時,伺服器端 Blazor 應用程式會包含適當的命名空間。 在用戶端端 Blazor 應用程式中,確認元件或應用程式的 Microsoft.AspNetCore.Authorization 檔案中是否存在 Microsoft.AspNetCore.Components.Authorization 和 _Imports.razor
命名空間:
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Components.Authorization
ProceduralLogic.razor
:
@page "/procedural-logic"
@inject IAuthorizationService AuthorizationService
<h1>Procedural Logic Example</h1>
<button @onclick="@DoSomething">Do something important</button>
@code {
[CascadingParameter]
private Task<AuthenticationState>? authenticationState { get; set; }
private async Task DoSomething()
{
if (authenticationState is not null)
{
var authState = await authenticationState;
var user = authState?.User;
if (user is not null)
{
if (user.Identity is not null && user.Identity.IsAuthenticated)
{
// ...
}
if (user.IsInRole("Admin"))
{
// ...
}
if ((await AuthorizationService.AuthorizeAsync(user, "content-editor"))
.Succeeded)
{
// ...
}
}
}
}
}
@page "/procedural-logic"
@inject IAuthorizationService AuthorizationService
<h1>Procedural Logic Example</h1>
<button @onclick="@DoSomething">Do something important</button>
@code {
[CascadingParameter]
private Task<AuthenticationState>? authenticationState { get; set; }
private async Task DoSomething()
{
if (authenticationState is not null)
{
var authState = await authenticationState;
var user = authState?.User;
if (user is not null)
{
if (user.Identity is not null && user.Identity.IsAuthenticated)
{
// ...
}
if (user.IsInRole("Admin"))
{
// ...
}
if ((await AuthorizationService.AuthorizeAsync(user, "content-editor"))
.Succeeded)
{
// ...
}
}
}
}
}
針對錯誤進行疑難排解
常見錯誤:
授權需要
Task<AuthenticationState>
類型的串聯參數。 請考慮使用CascadingAuthenticationState
來提供。null
的authenticationStateTask
值已接收
專案很可能不是使用已啟用驗證的伺服器端 Blazor 範本建立。
在 .NET 7 或更早的版本中,請將 <CascadingAuthenticationState>
包裹在 UI 結構的某些部分,例如包裹在 Blazor 路由器周圍:
<CascadingAuthenticationState>
<Router ...>
...
</Router>
</CascadingAuthenticationState>
在 .NET 8 或更新版本中,請勿使用 CascadingAuthenticationState 元件:
- <CascadingAuthenticationState>
<Router ...>
...
</Router>
- </CascadingAuthenticationState>
作為替代,請將串聯驗證狀態服務新增至 Program
檔案中的服務集合:
builder.Services.AddCascadingAuthenticationState();
CascadingAuthenticationState 元件 (.NET 7 或更早版本) 或 AddCascadingAuthenticationState 所提供的服務 (.NET 8 或更新版本) 提供 Task<
AuthenticationState>
累積參數,該參數進而從基礎 AuthenticationStateProvider 相依性注入服務中獲得。
個人識別資訊 (PII)
當文件涉及個人標識資訊 (PII) 時,Microsoft 是採用 GDPR 對「個人資料」的定義 (GDPR 4.1)。
PII 是指已識別或可識別自然人的任何相關資訊。 可識別的自然人是指可透過下列任一項內容,直接或間接識別的人員:
- 名稱
- 身分證號碼
- 位置座標
- 在線識別碼
- 其他特定因素
- 實體
- 生理
- 遺傳
- 心理 (精神)
- 經濟
- 文化
- 社會身分
其他資源
- 伺服器端和Blazor Web App資源
- 快速入門:將 Microsoft 登入功能新增至 ASP.NET Core Web 應用程式
- 快速入門:使用Microsoft身分識別平臺保護 ASP.NET Core Web API
-
設定 ASP.NET Core 以與 Proxy 伺服器和負載平衡器搭配運作:包含下列指引:
- 使用轉發標頭中介軟體來跨代理伺服器和內部網路保留 HTTPS 協定資訊。
- 其他情境和使用情境,包括手動方案設定、為了正確路由的請求路徑變更,以及轉送至 Linux 和非 IIS 反向代理的請求方案。
- Microsoft 身分識別平台文件
- ASP.NET Core 安全性主題
- 在 ASP.NET Core 中設定 Windows 驗證
- ASP.NET Core Blazor 應用程式中的 IHttpContextAccessor/HttpContext
- 建置 Authentication.MSAL JavaScript 程式庫的自訂版本
- 有趣的 Blazor:驗證 社群範例連結
- ASP.NET Core Blazor Hybrid 驗證與授權
- 伺服器端 Blazor 資源
- 快速入門:將 Microsoft 登入功能新增至 ASP.NET Core Web 應用程式
- 快速入門:使用Microsoft身分識別平臺保護 ASP.NET Core Web API
-
設定 ASP.NET Core 以與 Proxy 伺服器和負載平衡器搭配運作:包含下列指引:
- 使用轉發標頭中介軟體來跨代理伺服器和內部網路保留 HTTPS 協定資訊。
- 其他情境和使用情境,包括手動方案設定、為了正確路由的請求路徑變更,以及轉送至 Linux 和非 IIS 反向代理的請求方案。
- Microsoft 身分識別平台文件
- ASP.NET Core 安全性主題
- ASP.NET Core Blazor 應用程式中的 IHttpContextAccessor/HttpContext
- 在 ASP.NET Core 中設定 Windows 驗證
- 建置 Authentication.MSAL JavaScript 程式庫的自訂版本
- 有趣的 Blazor:驗證 社群範例連結