共用方式為


使用 Microsoft Entra ID 保護裝載的 ASP.NET Core Blazor WebAssembly 應用程式

本文說明如何建立使用 Microsoft Entra ID (ME-ID) 進行驗證的 託管 Blazor WebAssembly 解決方案。 本文著重於具有單一租用戶 Azure 應用程式註冊的單一租用戶應用程式。

本文未涵蓋多租用戶 ME-ID 註冊。 如需詳細資訊,請參閱讓應用程式成為多租用戶

本文主要說明如何使用 Microsoft Entra 租用戶,如快速入門:設定租用戶中所述。 如果應用程式已在 Azure Active Directory B2C 租用戶中註冊,如教學課程:建立 Azure Active Directory B2C 租用戶中所述,但遵循本文中的指引,應用程式識別碼 URI 會由 ME-ID 以不同的方式管理。 如需詳細資訊,請參閱本文的使用 Azure Active Directory B2C 租用戶一節。

在閱讀本文之後,如需其他安全性案例涵蓋範圍,請參閱 ASP.NET Core Blazor WebAssembly 其他安全性案例

逐步解說

逐步解說的子區段說明如何:

  • 在 Azure 中建立租用戶
  • 在 Azure 中註冊伺服器 API 應用程式
  • 在 Azure 中註冊用戶端應用程式
  • 建立 Blazor 應用程式
  • 修改 Server appsettings.json 設定
  • 修改預設存取權杖範圍配置
  • 執行應用程式

在 Azure 中建立租用戶

請遵循快速入門:設定租用戶中的指導,以在 ME-ID 中建立租用戶。

在 Azure 中註冊伺服器 API 應用程式

伺服器 API 應用程式註冊 ME-ID 應用程式:

  1. 在 Azure 入口網站中導覽至 Microsoft Entra ID。 選取資訊看板中的 [應用程式]>[應用程式註冊]。 選取 [新增註冊] 按鈕。
  2. 提供應用程式的名稱 (例如 Blazor Server ME-ID)。
  3. 選擇 [支援的帳戶類型]。 您可以針對此體驗選取 [僅在此組織目錄中的帳戶] (單一租用戶)。
  4. 在此案例中,伺服器 API 應用程式不需要重新導向 URI,因此請將 [選取平台] 下拉式清單保留為未選取狀態,且不要輸入重新導向 URI。
  5. 本文假設應用程式已在 Microsoft Entra 租用戶中註冊。 如果應用程式已在 Azure Active Directory B2C 租用戶中註冊,則會顯示 [權限]>[授與管理員同意 OpenID 和 offline_access 權限] 核取方塊並加以選取。 取消選取核取方塊以停用設定。 使用 Active Azure Directory 租用戶時,核取方塊不存在。
  6. 選取註冊

記錄下列資訊:

  • 伺服器 API 應用程式應用程式 (用戶端) 識別碼 (例如 00001111-aaaa-2222-bbbb-3333cccc4444)
  • 目錄 (租用戶) 識別碼 (例如 aaaabbbb-0000-cccc-1111-dddd2222eeee)
  • ME-ID 主要/發行者/租用戶網域 (例如 contoso.onmicrosoft.com):網域可在 Azure 入口網站中已註冊應用程式的 [商標] 刀鋒視窗中作為發行者網域

API 權限中,移除 Microsoft Graph>User.Read 權限,因為伺服器 API 應用程式不需要額外的 API 存取權,而只需要登入使用者和呼叫伺服器 API 端點。

在 [公開 API] 中:

  1. 確認或新增格式 api://{SERVER API APP CLIENT ID} 的 [應用程式識別碼 URI]
  2. 選取新增範圍
  3. 選取 [儲存並繼續] 。
  4. 提供範圍名稱 (例如 API.Access)。
  5. 提供管理員同意顯示名稱 (例如 Access API)。
  6. 提供管理員同意描述 (例如 Allows the app to access server app API endpoints.)。
  7. 確認 [狀態] 設定為 [已啟用]
  8. 選取新增範圍

記錄下列資訊:

  • 應用程式識別碼 URI GUID (例如,來自 api://00001111-aaaa-2222-bbbb-3333cccc4444 的應用程式識別碼 URI 的記錄 00001111-aaaa-2222-bbbb-3333cccc4444)
  • 範圍名稱 (例如 API.Access)

重要

如果針對應用程式識別碼 URI 使用自訂值,則從 Blazor WebAssembly 專案範本建立應用程式之後,ServerClient 應用程式都需要進行設定變更。 如需詳細資訊,請參閱使用自訂應用程式識別碼 URI 一節。

在 Azure 中註冊用戶端應用程式

註冊用戶端應用程式的 ME-ID 應用程式:

  1. 在 Azure 入口網站中導覽至 Microsoft Entra ID。 選取資訊看板中的 [應用程式註冊]。 選取 [新增註冊] 按鈕。
  2. 提供應用程式的名稱 (例如 Blazor 用戶端 ME-ID)。
  3. 選擇 [支援的帳戶類型]。 您可以針對此體驗選取 [僅在此組織目錄中的帳戶] (單一租用戶)。
  4. 將 [重新導向 URI] 下拉式清單設定為 [單頁應用程式 (SPA)],並提供下列重新導向 URI:https://localhost/authentication/login-callback。 如果您知道 Azure 預設主機 (例如 azurewebsites.net) 或自訂網域主機 (例如 contoso.com) 的生產重新導向 URI,您也可以在提供 localhost 重新導向 URI 的同時新增生產重新導向 URI。 請務必在您所新增的任何生產重新導向 URI 中包含非 :443 連接埠的連接埠號碼。
  5. 本文假設應用程式已在 Microsoft Entra 租用戶中註冊。 如果應用程式已在 Azure Active Directory B2C 租用戶中註冊,則會顯示 [權限]>[授與管理員同意 OpenID 和 offline_access 權限] 核取方塊並加以選取。 取消選取核取方塊以停用設定。 使用 Active Azure Directory 租用戶時,核取方塊不存在。
  6. 選取註冊

注意

不需要提供 localhost ME-ID 重新導向 URI 的連接埠號碼。 如需詳細資訊,請參閱重新導向 URI (回覆 URL) 限制:Localhost 例外狀況 (Entra 文件)

記錄 Client 應用程式的應用程式 (用戶端) 識別碼 (例如 11112222-bbbb-3333-cccc-4444dddd5555)。

在 [驗證]>[平台設定]>[單頁應用程式] 中:

  1. 確認 https://localhost/authentication/login-callback 的重新導向 URI 存在。
  2. 在 [隱含授與] 區段中,確定未選取 [存取權杖] 和 [識別碼權杖] 核取方塊。 不建議針對使用 MSAL v2.0 或更新版本的 Blazor 應用程式使用隱含授與。 如需詳細資訊,請參閱 保護 ASP.NET Core 的安全Blazor WebAssembly
  3. 此體驗可接受應用程式的其餘預設值。
  4. 如果您做了變更,請選取 [儲存] 按鈕。

在 [API 權限] 中:

  1. 確認應用程式具有 Microsoft Graph>User.Read 權限。
  2. 選取 [新增權限],然後是 [我的 API]
  3. 從 [名稱] 資料行選取 [伺服器 API 應用程式] (例如 Blazor Server ME-ID)。 您必須是應用程式註冊的擁有者 (如為個別的應用程式,則為 API 應用程式註冊),才能在 Azure 入口網站的 [我的 API] 區域中查看 API。 如需詳細資訊,請參閱指派應用程式擁有者 (Microsoft Entra 文件)
  4. 開啟 API 清單。
  5. 啟用對 API 的存取權 (例如 API.Access)。
  6. 選取新增權限
  7. 選取 [授與 {TENANT NAME} 的管理員同意] 按鈕。 選取 確認。

重要

如果您沒有在 [API 權限] 設定的最後一個步驟中授與系統管理員同意租用戶的權限,由於同意使用應用程式會委派給使用者,因此必須採取下列額外步驟:

  • 應用程式必須使用受信任的發行者網域
  • 在 Azure 入口網站的 Server 應用程式設定中,選取 [公開 API]。 在 [授權的用戶端應用程式] 底下,選取 [新增用戶端應用程式] 按鈕。 新增 Client 應用程式的應用程式 (用戶端) 識別碼 (例如 11112222-bbbb-3333-cccc-4444dddd5555)。

建立 Blazor 應用程式

在空白資料夾中,將下列命令中的預留位置取代為稍早記錄的資訊,並在命令殼層中執行命令:

dotnet new blazorwasm -au SingleOrg --api-client-id "{SERVER API APP CLIENT ID}" --app-id-uri "{SERVER API APP ID URI GUID}" --client-id "{CLIENT APP CLIENT ID}" --default-scope "{DEFAULT SCOPE}" --domain "{TENANT DOMAIN}" -ho -o {PROJECT NAME} --tenant-id "{TENANT ID}"

警告

避免在應用程式名稱 {PROJECT NAME} 中使用破折號 (-),這會破壞 OIDC 應用程式識別碼的形成。 Blazor WebAssembly 專案範本中的邏輯會使用方案設定中 OIDC 應用程式識別碼的專案名稱。 開頭大寫 (BlazorSample) 或底線 (Blazor_Sample) 是可接受的替代方案。 如需詳細資訊,請參閱裝載 Blazor WebAssembly 專案名稱中的破折號會破壞 OIDC 安全性 (dotnet/aspnetcore #35337)

預留位置 Azure 入口網站名稱 範例
{PROJECT NAME} BlazorSample
{CLIENT APP CLIENT ID} Client 應用程式的應用程式 (用戶端) 識別碼 11112222-bbbb-3333-cccc-4444dddd5555
{DEFAULT SCOPE} 範圍名稱 API.Access
{SERVER API APP CLIENT ID} 伺服器 API 應用程式的應用程式 (用戶端) 識別碼 00001111-aaaa-2222-bbbb-3333cccc4444
{SERVER API APP ID URI GUID} 應用程式識別碼 URI GUID 00001111-aaaa-2222-bbbb-3333cccc4444(僅限 GUID,符合 {SERVER API APP CLIENT ID}
{TENANT DOMAIN} 主要/發行者/租用戶網域 contoso.onmicrosoft.com
{TENANT ID} 目錄 (租用戶) 識別碼 aaaabbbb-0000-cccc-1111-dddd2222eeee

使用 -o|--output 選項指定的輸出位置會在專案資料夾不存在時建立專案資料夾,並且成為專案名稱的一部分。 避免在應用程式名稱中使用破折號 (-),這會破壞 OIDC 應用程式識別碼的形成 (請參閱先前的「警告」)。

重要

如果針對應用程式識別碼 URI 使用自訂值,則從 Blazor WebAssembly 專案範本建立應用程式之後,ServerClient 應用程式都需要進行設定變更。 如需詳細資訊,請參閱使用自訂應用程式識別碼 URI 一節。

執行應用程式

Server 專案執行應用程式。 使用 Visual Studio 時,請執行下列其中一項:

  • 選取 [執行] 按鈕旁的下拉式箭號。 從下拉式清單中開啟 [設定啟始專案]。 選取 [單一啟始專案] 選項。 確認或變更啟始專案的專案為 Server 專案。

  • 在使用下列任一方法啟動應用程式之前,請確認 Server 專案已在 [方案總管] 中醒目顯示:

    • 選取 [執行] 按鈕。
    • 從功能表使用 [偵錯]>[開始偵錯]
    • 請按 F5
  • 在命令殼層中,瀏覽至方案的 Server 專案資料夾。 執行 dotnet watch (或 dotnet run) 命令。

設定 User.Identity.Name

本節中的指導涵蓋選擇性地使用 name 宣告中的值填入 User.Identity.Name

Server 應用程式 API 會使用 http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name 宣告類型(例如 bbbb0000-cccc-1111-dddd-2222eeee3333@contoso.onmicrosoft.com)中的值填入 User.Identity.Name

若要將應用程式設定為從 name 宣告類型接收值:

方案的組件

本節描述從 Blazor WebAssembly 專案範本產生的方案組件,並描述如何設定方案的 ClientServer 專案以供參考。 如果您使用逐步解說一節中的指導來建立應用程式,則本節中沒有針對基本工作應用程式可遵循的任何特定指導。 本節中的指導有助於更新應用程式以驗證和授權使用者。 不過,更新應用程式的替代方法是從逐步解說一節中的指導建立新的應用程式,並將應用程式的元件、類別和資源移至新的應用程式。

appsettings.json 設定

本節與方案的 Server 應用程式有關。

檔案 appsettings.json 包含用來驗證存取權杖的 JWT 持有人處理常式選項。 新增下列 AzureAd 設定區段:

{
  "AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "Domain": "{TENANT DOMAIN}",
    "TenantId": "{TENANT ID}",
    "ClientId": "{SERVER API APP CLIENT ID}",
    "CallbackPath": "/signin-oidc",
    "Scopes": "{SCOPES}"
  }
}

範例:

{
  "AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "Domain": "contoso.onmicrosoft.com",
    "TenantId": "aaaabbbb-0000-cccc-1111-dddd2222eeee",
    "ClientId": "00001111-aaaa-2222-bbbb-3333cccc4444",
    "CallbackPath": "/signin-oidc",
    "Scopes": "API.Access"
  }
}

重要

如果 Server 應用程式已註冊為在 ME-ID 中使用自訂 App ID URI(不是預設格式 api://{SERVER API APP CLIENT ID}),請參閱 使用自訂應用程式識別碼 URI 一節。 ServerClient 應用程式中都需要變更。

驗證套件

本節與方案的 Server 應用程式有關。

套件會Microsoft.Identity.Web提供驗證和授權呼叫 ASP.NET Core Web API 與 Microsoft identity 平台的支援。

注意

如需將套件新增至 .NET 應用程式的指引,請參閱在套件取用工作流程 (NuGet 文件)安裝及管理套件底下的文章。 在 NuGet.org 確認正確的套件版本。

從 Blazor WebAssembly 範本所建立的託管 Blazor 解決方案的 Server 應用程式包含 Microsoft.Identity.Web.UI 套件。 套件會在 Web 應用程式中新增使用者驗證的 UI,且不會由 Blazor 架構使用。 如果 Server 應用程式不會用來直接驗證使用者,則可以安全地從 Server 應用程式的專案檔中移除套件參考。

驗證服務支援

本節與方案的 Server 應用程式有關。

AddAuthentication 方法會在應用程式內設定驗證服務,並將 JWT 持有人處理常式設定為預設驗證方法。 方法 AddMicrosoftIdentityWebApi 會將服務設定為使用 Microsoft identity 平臺 v2.0 來保護 Web API。 此方法預期應用程式設定中有一個 AzureAd 區段,其中包含初始化驗證選項的必要設定。

builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApi(Configuration.GetSection("AzureAd"));

注意

註冊單一驗證配置時,驗證配置會自動用作應用程式的預設配置,而且不需要向 AddAuthentication 或透過 AuthenticationOptions 陳述該配置。 如需詳細資訊,請參閱 ASP.NET Core 驗證概觀ASP.NET Core 公告 (aspnet/Announcements #490)

UseAuthenticationUseAuthorization 可確保:

  • 應用程式會嘗試剖析和驗證傳入要求上的權杖。
  • 任何嘗試存取受保護資源而沒有適當認證的要求都會失敗。
app.UseAuthentication();
app.UseAuthorization();

WeatherForecast 控制器

本節與方案的 Server 應用程式有關。

WeatherForecast 控制器 (Controllers/WeatherForecastController.cs) 會公開受保護的 API, 並將 [Authorize] 屬性套用至控制器。 請務必了解:

  • 此 API 控制器中的 [Authorize] 屬性是保護此 API 免於未經授權存取的唯一屬性。
  • Blazor WebAssembly 應用程式中使用的 [Authorize] 屬性只會用作應用程式提示,指出使用者應獲得授權才能讓應用程式正常運作。
[Authorize]
[ApiController]
[Route("[controller]")]
[RequiredScope(RequiredScopesConfigurationKey = "AzureAd:Scopes")]
public class WeatherForecastController : ControllerBase
{
    [HttpGet]
    public IEnumerable<WeatherForecast> Get()
    {
        ...
    }
}

wwwroot/appsettings.json 設定

本節與方案的 Client 應用程式有關。

wwwroot/appsettings.json 檔案會提供設定:

{
  "AzureAd": {
    "Authority": "https://login.microsoftonline.com/{TENANT ID}",
    "ClientId": "{CLIENT APP CLIENT ID}",
    "ValidateAuthority": true
  }
}

範例:

{
  "AzureAd": {
    "Authority": "https://login.microsoftonline.com/e86c78e2-...-918e0565a45e",
    "ClientId": "11112222-bbbb-3333-cccc-4444dddd5555",
    "ValidateAuthority": true
  }
}

驗證套件

本節與方案的 Client 應用程式有關。

建立應用程式以使用公司或學校帳戶 (SingleOrg) 時,應用程式會自動收到 Microsoft 驗證程式庫 (Microsoft.Authentication.WebAssembly.Msal) 的套件參考。 套件提供一組基本類型,可協助應用程式驗證使用者,並取得權杖來呼叫受保護的 API。

如果將驗證新增至應用程式,請手動將 Microsoft.Authentication.WebAssembly.Msal 套件新增至應用程式。

注意

如需將套件新增至 .NET 應用程式的指引,請參閱在套件取用工作流程 (NuGet 文件)安裝及管理套件底下的文章。 在 NuGet.org 確認正確的套件版本。

Microsoft.Authentication.WebAssembly.Msal 套件可轉移性地將 Microsoft.AspNetCore.Components.WebAssembly.Authentication 套件新增至應用程式。

驗證服務支援

本節與方案的 Client 應用程式有關。

新增了 HttpClient 執行個體的支援,包括對 Server 應用程式提出要求時的存取權杖。

Program 檔案中:

builder.Services.AddHttpClient("{PROJECT NAME}.ServerAPI", client => 
        client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress))
    .AddHttpMessageHandler<BaseAddressAuthorizationMessageHandler>();

builder.Services.AddScoped(sp => sp.GetRequiredService<IHttpClientFactory>()
    .CreateClient("{PROJECT NAME}.ServerAPI"));

{PROJECT NAME} 預留位置是方案建立時的專案名稱。 例如,提供 BlazorSample 的專案名稱會產生名為 HttpClientBlazorSample.ServerAPI

支援使用 Microsoft.Authentication.WebAssembly.Msal 套件所提供的 AddMsalAuthentication 擴充方法,驗證在服務容器中註冊的使用者。 這個方法會設定應用程式與 Identity 提供者 (IP) 互動所需的服務。

Program 檔案中:

builder.Services.AddMsalAuthentication(options =>
{
    builder.Configuration.Bind("AzureAd", options.ProviderOptions.Authentication);
    options.ProviderOptions.DefaultAccessTokenScopes.Add("{SCOPE URI}");
});

AddMsalAuthentication 方法接受回呼,以設定驗證應用程式所需的參數。 當您註冊應用程式時,可以從 Azure 入口網站 ME-ID 設定取得設定所需的值。

存取權杖範圍

本節與方案的 Client 應用程式有關。

預設存取權杖範圍代表下列存取權杖範圍的清單:

  • 包含在登入要求中。
  • 用來在驗證之後立即佈建存取權杖。

您可以視需要在 Program 檔案中新增其他範圍:

builder.Services.AddMsalAuthentication(options =>
{
    ...
    options.ProviderOptions.DefaultAccessTokenScopes.Add("{SCOPE URI}");
});

使用 AdditionalScopesToConsent 指定其他範圍:

options.ProviderOptions.AdditionalScopesToConsent.Add("{ADDITIONAL SCOPE URI}");

注意

當使用者第一次使用在 Microsoft Azure 中註冊的應用程式時,AdditionalScopesToConsent 無法透過 Microsoft Entra ID 同意 UI 來佈建 Microsoft Graph 的委派使用者權限。 如需詳細資訊,請參閱搭配使用 Graph API 與 ASP.NET Core Blazor WebAssembly

範例預設存取權杖範圍:

options.ProviderOptions.DefaultAccessTokenScopes.Add(
    "api://00001111-aaaa-2222-bbbb-3333cccc4444/API.Access");

如需詳細資訊,請參閱其他案例文章的下列各節:

登入模式

本節與方案的 Client 應用程式有關。

如果無法開啟快顯項目,架構預設為快顯登入模式,並回復為重新導向登入模式。 將 MsalProviderOptionsLoginMode 屬性設定為 redirect,設定 MSAL 以使用重新導向登入模式:

builder.Services.AddMsalAuthentication(options =>
{
    ...
    options.ProviderOptions.LoginMode = "redirect";
});

預設設定為 popup,且字串值不區分大小寫。

匯入檔案

本節與方案的 Client 應用程式有關。

Microsoft.AspNetCore.Components.Authorization 命名空間可透過 _Imports.razor 檔案在整個應用程式中使用:

@using System.Net.Http
@using System.Net.Http.Json
@using Microsoft.AspNetCore.Components.Authorization
@using Microsoft.AspNetCore.Components.Forms
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.Web
@using Microsoft.AspNetCore.Components.Web.Virtualization
@using Microsoft.AspNetCore.Components.WebAssembly.Http
@using Microsoft.JSInterop
@using {APPLICATION ASSEMBLY}
@using {APPLICATION ASSEMBLY}.Shared

索引頁面

本節與方案的 Client 應用程式有關。

[索引] 頁面 (wwwroot/index.html) 頁面包含一個指令碼,定義 JavaScript 中的 AuthenticationServiceAuthenticationService 會處理 OIDC 通訊協定的低階詳細資料。 應用程式會在內部呼叫指令碼中定義的方法,來執行驗證作業。

<script src="_content/Microsoft.Authentication.WebAssembly.Msal/AuthenticationService.js"></script>

應用程式元件

本節與方案的 Client 應用程式有關。

App 元件 (App.razor) 類似於在 Blazor Server 應用程式中找到的 App 元件:

由於 ASP.NET Core 版本之間的架構變更,所以本節不會顯示 App 元件的 Razor 標記 (App.razor)。 若要檢查指定版本的元件標記,請使用下列任一方法:

  • 針對您想要使用的 ASP.NET Core 版本,從預設 Blazor WebAssembly 專案範本建立要佈建以進行驗證的應用程式。 在產生的應用程式中檢查 App 元件 (App.razor)。

  • 參考來源中檢查 App 元件 (App.razor)。 從分支選取器中選擇版本,然後在存放庫的 ProjectTemplates 資料夾中搜尋該元件,因為 App 元件的位置多年來已經移動。

    注意

    .NET 參考來源的文件連結通常會載入存放庫的預設分支,這表示下一版 .NET 的目前開發。 若要選取特定版本的標籤,請使用 [切換分支或標籤] 下拉式清單。 如需詳細資訊,請參閱如何選取 ASP.NET Core 原始程式碼 (dotnet/AspNetCore.Docs #26205) 的版本標籤

RedirectToLogin 元件

本節與方案的 Client 應用程式有關。

RedirectToLogin 元件 (RedirectToLogin.razor):

  • 管理將未經授權的使用者重新導向至登入頁面。
  • 使用者嘗試存取的目前 URL 會如此進行維護,以便在驗證成功時返回該頁面:
    • .NET 7 或更新版本中 ASP.NET Core 中的瀏覽歷程記錄狀態
    • .NET 6 或更早版本中 ASP.NET Core 中的查詢字串。

參考來源中檢查 RedirectToLogin 元件。 該元件的位置已隨著時間而變更,因此請使用 GitHub 搜尋工具來找出該元件。

注意

.NET 參考來源的文件連結通常會載入存放庫的預設分支,這表示下一版 .NET 的目前開發。 若要選取特定版本的標籤,請使用 [切換分支或標籤] 下拉式清單。 如需詳細資訊,請參閱如何選取 ASP.NET Core 原始程式碼 (dotnet/AspNetCore.Docs #26205) 的版本標籤

LoginDisplay 元件

本節與方案的 Client 應用程式有關。

LoginDisplay 元件 (LoginDisplay.razor) 是在 MainLayout 元件 (MainLayout.razor) 中進行轉譯,並且管理下列行為:

  • 針對已驗證的使用者:
    • 顯示目前的使用者名稱。
    • 提供 ASP.NET Core Identity 中使用者設定檔頁面的連結。
    • 提供登出應用程式的按鈕。
  • 針對匿名使用者:
    • 提供註冊的選項。
    • 提供登入的選項。

由於 ASP.NET Core 版本之間的架構變更,所以本節不會顯示 LoginDisplay 元件的 Razor 標記。 若要檢查指定版本的元件標記,請使用下列任一方法:

  • 針對您想要使用的 ASP.NET Core 版本,從預設 Blazor WebAssembly 專案範本建立要佈建以進行驗證的應用程式。 在產生的應用程式中檢查 LoginDisplay 元件。

  • 參考來源中檢查 LoginDisplay 元件。 該元件的位置已隨著時間而變更,因此請使用 GitHub 搜尋工具來找出該元件。 使用等於 trueHosted 範本化內容。

    注意

    .NET 參考來源的文件連結通常會載入存放庫的預設分支,這表示下一版 .NET 的目前開發。 若要選取特定版本的標籤,請使用 [切換分支或標籤] 下拉式清單。 如需詳細資訊,請參閱如何選取 ASP.NET Core 原始程式碼 (dotnet/AspNetCore.Docs #26205) 的版本標籤

驗證元件

本節與方案的 Client 應用程式有關。

Authentication 元件 (Pages/Authentication.razor) 所產生的頁面會定義處理不同驗證階段所需的路由。

RemoteAuthenticatorView 元件:

@page "/authentication/{action}"
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication

<RemoteAuthenticatorView Action="@Action" />

@code {
    [Parameter]
    public string? Action { get; set; }
}

注意

.NET 6 或更新版本中的 ASP.NET Core 中支援可為 Null 參考型別 (NRT) 和 .NET 編譯器 Null 狀態靜態分析。 在 .NET 6 中的 ASP.NET Core 發行之前,string 類型並沒有 Null 類型指定 (?)。

FetchData 元件

本節與方案的 Client 應用程式有關。

FetchData 元件會示範如何:

  • 佈建存取權杖。
  • 使用該存取權杖來呼叫 Server 應用程式中的受保護資源 API。

@attribute [Authorize] 指示詞會向 Blazor WebAssembly 授權系統指示使用者必須獲得授權才能存取此元件。 Client 應用程式中該屬性的存在不會阻止在沒有適當認證的情況下呼叫伺服器上的 API。 Server 應用程式也必須在適當的端點上使用 [Authorize] 才能正確地提供保護。

IAccessTokenProvider.RequestAccessToken 負責要求索取可新增至要求以呼叫 API 的存取權杖。 如果權杖已快取或服務能夠在無需使用者互動的情況下提供新的存取權杖,則要求索取權杖會成功。 否則,要求索取權杖會失敗並出現 AccessTokenNotAvailableException (它會在 try-catch 陳述式中攔截)。

為了取得要包含在要求中的實際權杖,應用程式必須透過呼叫 tokenResult.TryGetToken(out var token) 來檢查要求索取是否成功。

如果要求索取成功,則會使用存取權杖來填入 token 變數。 權杖的 AccessToken.Value 屬性會公開要包含在 Authorization 要求標頭中的常值字串。

如果因在沒有使用者互動的情況下無法提供權杖而要求索取失敗,則:

  • .NET 7 或更新版本中的 ASP.NET Core:應用程式會使用指定的 AccessTokenResult.InteractionOptions 瀏覽至 AccessTokenResult.InteractiveRequestUrl 以允許重新整理存取權杖。
  • .NET 6 或更早版本中的 ASP.NET Core:權杖結果會包含重新導向 URL。 瀏覽至此 URL 會將使用者帶到登入頁面,並在驗證成功之後回到目前的頁面。
@page "/fetchdata"
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@using {APP NAMESPACE}.Shared
@attribute [Authorize]
@inject HttpClient Http

...

@code {
    private WeatherForecast[] forecasts;

    protected override async Task OnInitializedAsync()
    {
        try
        {
            forecasts = await Http.GetFromJsonAsync<WeatherForecast[]>("WeatherForecast");
        }
        catch (AccessTokenNotAvailableException exception)
        {
            exception.Redirect();
        }
    }
}

使用 Azure Active Directory B2C 租用戶

如果應用程式已在 Azure Active Directory B2C 租用戶中註冊,如教學課程:建立 Azure Active Directory B2C 租用戶中所述,但遵循本文中的指引,應用程式識別碼 URI 會由 ME-ID 以不同的方式管理。

您可以選取 ME-ID 組織 [概觀] 頂端的 [管理租用戶] 連結,以檢查現有租用戶的租用戶類型。 檢查組織的租用戶類型資料行值。 本節與本文中遵循指引但已在 Azure Active Directory B2C 租用戶中註冊的應用程式有關。

並非符合格式 api://{SERVER API APP CLIENT ID OR CUSTOM VALUE} 的應用程式識別碼 URI,應用程式識別碼 URI 的格式為 https://{TENANT}.onmicrosoft.com/{SERVER API APP CLIENT ID OR CUSTOM VALUE}。 此差異會影響 ClientServer 應用程式設定:

  • 針對伺服器 API 應用程式,在應用程式設定檔 (appsettings.json) 中設定 Audience,以符合 Azure 入口網站所提供的應用程式適用對象 (應用程式識別碼 URI),不含尾端斜線:

    "Audience": "https://{TENANT}.onmicrosoft.com/{SERVER API APP CLIENT ID OR CUSTOM VALUE}"
    

    範例:

    "Audience": "https://contoso.onmicrosoft.com/00001111-aaaa-2222-bbbb-3333cccc4444"
    
  • Client 應用程式的 Program 檔案中,將範圍的適用對象 (應用程式識別碼 URI) 設定為符合伺服器 API 應用程式的物件:

    options.ProviderOptions.DefaultAccessTokenScopes
        .Add("https://{TENANT}.onmicrosoft.com/{SERVER API APP CLIENT ID OR CUSTOM VALUE}/{DEFAULT SCOPE}");
    

    在上述範圍中,應用程式識別碼 URI/適用對象是值的 https://{TENANT}.onmicrosoft.com/{SERVER API APP CLIENT ID OR CUSTOM VALUE} 部分,其中不包含尾端斜線 (/),且不包含範圍名稱 ({DEFAULT SCOPE})。

    範例:

    options.ProviderOptions.DefaultAccessTokenScopes
        .Add("https://contoso.onmicrosoft.com/00001111-aaaa-2222-bbbb-3333cccc4444/API.Access");
    

    在上述範圍中,應用程式識別碼 URI/適用對象是值的 https://contoso.onmicrosoft.com/00001111-aaaa-2222-bbbb-3333cccc4444 部分,其中不包含尾端斜線 (/),且不包含範圍名稱 (API.Access)。

使用自訂應用程式識別碼 URI

如果應用程式識別碼 URI 是自訂值,您必須手動更新 Client 應用程式中的預設存取權杖範圍 URI,並將適用對象新增至 Server 應用程式的 ME-ID 設定。

重要

使用 api://{SERVER API APP CLIENT ID} 的預設應用程式識別碼 URI 時,不需要下列設定。

urn://custom-app-id-uri 的範例應用程式識別碼 URI 和 API.Access 的範圍名稱:

  • Client 應用程式的 Program 檔案中:

    options.ProviderOptions.DefaultAccessTokenScopes.Add(
        "urn://custom-app-id-uri/API.Access");
    
  • Server 應用程式的 appsettings.json 中,新增只有應用程式識別碼 URI 且沒有尾端斜線的 Audience 項目:

    "Audience": "urn://custom-app-id-uri"
    

疑難排解

記錄

若要啟用 Blazor WebAssembly 驗證的偵錯或追蹤記錄,請參閱 ASP.NET Core Blazor 記錄用戶端驗證記錄一節,並將發行項版本選取器設定為 ASP.NET Core 7.0 或更新版本。

常見錯誤

  • 應用程式或 Identity 提供者 (IP) 的設定錯誤

    最常見的錯誤是由不正確的設定所造成。 以下是一些範例:

    • 視案例的需求而定,遺漏或不正確的授權單位、執行個體、租用戶識別碼、租用戶網域、用戶端識別碼或重新導向 URI 會防止應用程式驗證用戶端。
    • 不正確的要求範圍會防止用戶端存取伺服器 Web API 端點。
    • 不正確或遺漏伺服器 API 權限會防止用戶端存取伺服器 Web API 端點。
    • 在與 IP 應用程式註冊的重新導 URI 中設定的連接埠不同的連接埠上執行應用程式。 請注意,Microsoft Entra ID 和在 localhost 開發測試位址執行的應用程式不需要連接埠,但應用程式的連接埠設定和應用程式執行的連接埠必須與非 localhost 位址相符。

    本文指導的設定區段顯示正確設定的範例。 仔細查看文章中有關尋找應用程式和 IP 設定錯誤的每個區段。

    如果設定顯示正確:

    • 分析應用程式記錄檔。

    • 使用瀏覽器的開發人員工具,檢查用戶端應用程式與 IP 或伺服器應用程式之間的網路流量。 通常,在提出要求之後,IP 或伺服器應用程式會傳回錯誤訊息或有導致問題的線索訊息給用戶端。 下列文章中可找到開發人員工具指導:

    • 對於使用 JSON Web 權杖 (JWT) 的 Blazor 版本,根據問題發生的位置,對用於驗證用戶端或存取伺服器 Web API 的權杖內容進行解碼。 如需詳細資訊,請參閱 檢查 JSON Web 權杖 (JWT) 的內容

    文件小組會回應文章中的文件意見反應和 BUG (從此頁面意見反應區段開啟問題),但是無法提供產品支援。 有數個公用支援論壇可用來協助針對應用程式進行疑難排解。 我們建議下列事項:

    上述論壇並非由 Microsoft 擁有或控制。

    針對非安全性、非敏感性和非機密可重現架構 BUG 報告,向 ASP.NET Core 產品單位提出問題。 在您徹底調查問題的原因而且無法自行解決,並取得公用支援論壇上社群的協助之前,請勿向產品單位提出問題。 產品單位無法針對因簡單設定錯誤或涉及第三方服務的使用案例而中斷的個別應用程式進行疑難排解。 如果報告具有敏感性或機密性質,或描述了攻擊者可能惡意探索的產品中潛在的安全性缺陷,請參閱 報告安全性問題和 BUG (dotnet/aspnetcore GitHub 存放庫)

  • ME-ID 未經授權的用戶端

    info: Microsoft.AspNetCore.Authorization.DefaultAuthorizationService[2] Authorization failed. 不符合以下需求: DenyAnonymousAuthorizationRequirement:需要已驗證的使用者。

    ME-ID 的登入回呼錯誤:

    • 錯誤: unauthorized_client
    • 描述:AADB2C90058: The provided application is not configured to allow public clients.

    若要解決此錯誤:

    1. 在 Azure 入口網站中,存取應用程式的資訊清單
    2. allowPublicClient 屬性設定為 nulltrue

Cookie 和網站資料

Cookie 和網站資料可以在應用程式更新之間保存,並可介入測試和疑難排解。 進行應用程式程式碼變更、使用提供者的使用者帳戶變更,或提供者應用程式設定變更時,請清除下列內容:

  • 使用者登入 Cookie
  • 應用程式 Cookie
  • 快取和儲存的網站資料

防止徘徊的 cookie 和網站資料不會因使用測試和疑難排解而介入的一種方法是:

  • 設定瀏覽器
    • 使用瀏覽器進行測試,您可以設定在每次關閉瀏覽器時刪除所有 cookie 和網站資料。
    • 請確定瀏覽器已手動關閉或由 IDE 關閉,以便對應用程式、測試使用者或提供者設定進行任何變更。
  • 使用自訂命令,在 Visual Studio 中以私人模式或無痕模式開啟瀏覽器:
    • 從 Visual Studio 的 [執行] 按鈕開啟 [瀏覽方式] 對話方塊。
    • 選取新增按鈕。
    • 在 [程式] 欄位中提供瀏覽器的路徑。 下列可執行檔路徑是 Windows 10 的一般安裝位置。 如果您的瀏覽器安裝在不同的位置,或您不是使用 Windows 10,請提供瀏覽器可執行檔的路徑。
      • Microsoft Edge:C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe
      • Google Chrome:C:\Program Files (x86)\Google\Chrome\Application\chrome.exe
      • Mozilla Firefox:C:\Program Files\Mozilla Firefox\firefox.exe
    • 在 [引數] 欄位中,提供瀏覽器用來在私人模式或無痕模式中開啟的命令列選項。 某些瀏覽器需要應用程式的 URL。
      • Microsoft Edge:使用 -inprivate
      • Google Chrome:使用 --incognito --new-window {URL},其中 {URL} 預留位置是要開啟的 URL (例如 https://localhost:5001)。
      • Mozilla Firefox:使用 -private -url {URL},其中 {URL} 預留位置是要開啟的 URL (例如 https://localhost:5001)。
    • 在 [自訂名稱] 欄位中提供名稱。 例如: Firefox Auth Testing
    • 選取確定按鈕。
    • 若要避免針對使用應用程式測試的每個反覆項目選取瀏覽器設定檔,請使用 [設為預設值] 按鈕,將設定檔設定為預設值。
    • 請確定瀏覽器已由 IDE 關閉,以便對應用程式、測試使用者或提供者設定進行任何變更。

應用程式升級

在升級開發電腦上的 .NET Core SDK 或變更應用程式內的套件版本之後,正常運作的應用程式便立即發生失敗。 在某些情況下,執行主要升級時,不一致的套件可能會中斷應用程式。 大多數這些問題都可依照下列指示來進行修正:

  1. 從命令殼層執行 dotnet nuget locals all --clear,以清除本機系統的 NuGet 套件快取。
  2. 刪除專案的 binobj 資料夾。
  3. 還原並重建專案。
  4. 在重新部署應用程式之前,請先刪除伺服器上部署資料夾中的所有檔案。

注意

不支援使用與應用程式目標框架不相容的套件版本。 如需套件的詳細資訊,請使用 NuGet 資源庫FuGet 套件總管

執行 Server 應用程式

測試裝載 Blazor WebAssembly方案並且進行疑難排解時,請確定您是從 Server 專案執行應用程式。

檢查使用者

下列 User 元件可以直接在應用程式中使用,或作為進一步自訂的基礎。

User.razor

@page "/user"
@attribute [Authorize]
@using System.Text.Json
@using System.Security.Claims
@inject IAccessTokenProvider AuthorizationService

<h1>@AuthenticatedUser?.Identity?.Name</h1>

<h2>Claims</h2>

@foreach (var claim in AuthenticatedUser?.Claims ?? Array.Empty<Claim>())
{
    <p class="claim">@(claim.Type): @claim.Value</p>
}

<h2>Access token</h2>

<p id="access-token">@AccessToken?.Value</p>

<h2>Access token claims</h2>

@foreach (var claim in GetAccessTokenClaims())
{
    <p>@(claim.Key): @claim.Value.ToString()</p>
}

@if (AccessToken != null)
{
    <h2>Access token expires</h2>

    <p>Current time: <span id="current-time">@DateTimeOffset.Now</span></p>
    <p id="access-token-expires">@AccessToken.Expires</p>

    <h2>Access token granted scopes (as reported by the API)</h2>

    @foreach (var scope in AccessToken.GrantedScopes)
    {
        <p>Scope: @scope</p>
    }
}

@code {
    [CascadingParameter]
    private Task<AuthenticationState> AuthenticationState { get; set; }

    public ClaimsPrincipal AuthenticatedUser { get; set; }
    public AccessToken AccessToken { get; set; }

    protected override async Task OnInitializedAsync()
    {
        await base.OnInitializedAsync();
        var state = await AuthenticationState;
        var accessTokenResult = await AuthorizationService.RequestAccessToken();

        if (!accessTokenResult.TryGetToken(out var token))
        {
            throw new InvalidOperationException(
                "Failed to provision the access token.");
        }

        AccessToken = token;

        AuthenticatedUser = state.User;
    }

    protected IDictionary<string, object> GetAccessTokenClaims()
    {
        if (AccessToken == null)
        {
            return new Dictionary<string, object>();
        }

        // header.payload.signature
        var payload = AccessToken.Value.Split(".")[1];
        var base64Payload = payload.Replace('-', '+').Replace('_', '/')
            .PadRight(payload.Length + (4 - payload.Length % 4) % 4, '=');

        return JsonSerializer.Deserialize<IDictionary<string, object>>(
            Convert.FromBase64String(base64Payload));
    }
}

檢查 JSON Web 權杖 (JWT) 的內容

若要解碼 JSON Web 權杖 (JWT),請使用 Microsoft 的 jwt.ms 工具。 UI 中的值永遠不會離開瀏覽器。

範例編碼 JWT (已縮短顯示):

eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6Ilg1ZVhrNHh5b2pORnVtMWtsMll0djhkbE5QNC1j ... bQdHBHGcQQRbW7Wmo6SWYG4V_bU55Ug_PW4pLPr20tTS8Ct7_uwy9DWrzCMzpD-EiwT5IjXwlGX3IXVjHIlX50IVIydBoPQtadvT7saKo1G5Jmutgq41o-dmz6-yBMKV2_nXA25Q

針對 Azure AAD B2C 進行驗證之應用程式的工具所解碼的範例 JWT:

{
  "typ": "JWT",
  "alg": "RS256",
  "kid": "X5eXk4xyojNFum1kl2Ytv8dlNP4-c57dO6QGTVBwaNk"
}.{
  "exp": 1610059429,
  "nbf": 1610055829,
  "ver": "1.0",
  "iss": "https://mysiteb2c.b2clogin.com/11112222-bbbb-3333-cccc-4444dddd5555/v2.0/",
  "sub": "aaaaaaaa-0000-1111-2222-bbbbbbbbbbbb",
  "aud": "00001111-aaaa-2222-bbbb-3333cccc4444",
  "nonce": "bbbb0000-cccc-1111-dddd-2222eeee3333",
  "iat": 1610055829,
  "auth_time": 1610055822,
  "idp": "idp.com",
  "tfp": "B2C_1_signupsignin"
}.[Signature]

其他資源