Share via


使用 OpenID Connect (OIDC) 保護 ASP.NET Core Blazor Web 應用程式

本文說明如何使用 dotnet/blazor-samples GitHub 存放庫 (.NET 8 或更新版本) (如何下載) 中的應用程式範例,使用 OpenID Connect (OIDC) 保護 Blazor Web 應用程式。

這個版本的發行項包含不採用前端的後端 (BFF) 模式實作 OIDC。 BFF 模式適用於對外部服務提出已驗證的要求。 如果應用程式的規格要求採用 BFF 模式,請將發行項版本選取器變更為使用 BFF 的 OIDC 模式

涵蓋下列規格:

  • Blazor Web 應用程式使用自動轉譯模式搭配全域互動
  • 伺服器和用戶端應用程式使用自訂驗證狀態提供者服務擷取使用者的驗證狀態,並在伺服器與客戶端之間流動。
  • 這個應用程式是任何 OIDC 驗證流程的起點。 OIDC 在應用程式手動設定,且不採用 Microsoft Entra IDMicrosoft Identity Web 套件,應用程式範例也不需要 Microsoft Azure 裝載。 不過,應用程式範例可與 Entra、Microsoft Identity Web 搭配使用,並且裝載於 Azure。
  • 自動非互動式權杖重新整理。
  • 在伺服器專案安全呼叫 (web) API 以取得資料。

範例應用程式

這個應用程式範例包含二個專案:

  • BlazorWebAppOidc:Blazor Web 應用程式的伺服器端專案,包含天氣資料的最小 API 端點範例。
  • BlazorWebAppOidc.Client:Blazor Web 應用程式的用戶端專案。

請使用下列連結,透過存放庫根目錄中的最新版本資料夾存取應用程式範例。 專案位於 .NET 8 或更新版本的 BlazorWebAppOidc 資料夾。

檢視或下載範例程式碼 \(英文\) (如何下載)

伺服器端 Blazor Web 應用程式專案 (BlazorWebAppOidc)

BlazorWebAppOidc 專案是 Blazor Web 應用程式的伺服器端專案。

BlazorWebAppOidc.http 檔案可用於測試天氣資料要求。 請注意,BlazorWebAppOidc 專案必須執行才能測試端點,而且端點會硬式編碼到檔案中。 如需詳細資訊,請參閱在 Visual Studio 2022 中使用 .http 檔案

注意

伺服器專案會使用 IHttpContextAccessor/HttpContext,但絕不會用於互動式轉譯的元件。 如需詳細資訊,請參閱 ASP.NET Core Blazor 互動式伺服器端轉譯的威脅風險降低指導

組態

本節說明如何設定應用程式範例。

注意

針對 Microsoft Entra ID 和 Azure AD B2C,您可以使用來自 Microsoft Identity WebAddMicrosoftIdentityWebApp (Microsoft.Identity.Web NuGet 套件API 文件),而且它同時會新增 OIDC 和具有適當預設值的 Cookie 驗證處理常式。 本節中的應用程式範例和指導不使用 Microsoft Identity Web。 這份指導示範如何為任何 OIDC 提供者手動設定 OIDC 處理常式。 如需實作 Microsoft Identity Web 的詳細資訊,請參閱連結的資源。

呼叫 AddOpenIdConnect 時,在專案的 Program 檔案找到下列 OpenIdConnectOptions設定:

  • SignInScheme:設定與在成功驗證後負責保存使用者身分識別之中介軟體對應的驗證配置。 OIDC 處理常式必須使用能夠跨要求保存使用者認證的登入配置。 下方這一行字僅供示範之用。 如果省略,則會使用 DefaultSignInScheme 做為備用值。

    oidcOptions.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    
  • openidprofile (Scope) 的範圍 (選擇性):預設也會設定 openidprofile 範圍,因為 OIDC 處理常式需要它們才能運作,但如果 Authentication:Schemes:MicrosoftOidc:Scope 設定包含範圍,則可能必須重新新增這些範圍。 如需一般設定指導,請參閱 ASP.NET Core 中的設定ASP.NET Core Blazor 設定

    oidcOptions.Scope.Add(OpenIdConnectScope.OpenIdProfile);
    
  • SaveTokens:定義了在成功授權之後,是否應該將存取和重新整理權杖儲存在 AuthenticationProperties 中。 預設會將這個屬性設為 false,以減少最終驗證 cookie 的大小。

    oidcOptions.SaveTokens = false;
    
  • 離線存取的範圍 (Scope):重新整理權杖需要 offline_access 範圍。

    oidcOptions.Scope.Add(OpenIdConnectScope.OfflineAccess);
    
  • AuthorityClientId:設定 OIDC 呼叫的授權單位和用戶端識別碼。

    oidcOptions.Authority = "{AUTHORITY}";
    oidcOptions.ClientId = "{CLIENT ID}";
    

    範例:

    • 授權單位 ({AUTHORITY}):https://login.microsoftonline.com/a3942615-d115-4eb7-bc84-9974abcf5064/v2.0/ (使用租用戶標識碼 a3942615-d115-4eb7-bc84-9974abcf5064)
    • 用戶端識別碼 ({CLIENT ID}):4ba4de56-9cef-45d9-83fa-a4c18f9f5f0f
    oidcOptions.Authority = "https://login.microsoftonline.com/a3942615-d115-4eb7-bc84-9974abcf5064/v2.0/";
    oidcOptions.ClientId = "4ba4de56-9cef-45d9-83fa-a4c18f9f5f0f";
    

    Microsoft Azure「通用」授權單位的範例:

    「通用」授權單位應該用於多租用戶應用程式。 您也可以針對單一租用戶應用程式使用「通用」授權單位,但需要有自訂的 IssuerValidator,如本節稍後所示。

    oidcOptions.Authority = "https://login.microsoftonline.com/common/v2.0/";
    
  • ClientSecret:OIDC 用戶端密碼。

    下列範例僅供測試與示範之用。 請勿將用戶端密碼儲存在應用程式的組件中,也不要將秘密提交到原始檔控制。 將用戶端密碼儲存於使用者祕密Azure Key Vault環境變數

    驗證配置設定會從 builder.Configuration["Authentication:Schemes:{SCHEME NAME}:{PropertyName}"] 自動讀取,其中 {SCHEME NAME} 預留位置是配置,預設為 MicrosoftOidc。 由於設定已預先設定,因此可以透過 Authentication:Schemes:MicrosoftOidc:ClientSecret 設定金鑰自動讀取用戶端密碼。 在使用環境變數的伺服器,將環境變數命名為 Authentication__Schemes__MicrosoftOidc__ClientSecret

    set Authentication__Schemes__MicrosoftOidc__ClientSecret={CLIENT SECRET}
    

    僅供示範和測試之用,可以直接設定 ClientSecret。 請勿為已部署的實際執行應用程式直接設定值。 為了稍微提升安全性,請以有條件的方式編譯DEBUG 符號的這行文字:

    #if DEBUG
    oidcOptions.ClientSecret = "{CLIENT SECRET}";
    #endif
    

    範例:

    用戶端密碼 ({CLIENT SECRET}):463471c8c4...f90d674bc9 (為顯示而縮短)

    #if DEBUG
    oidcOptions.ClientSecret = "463471c8c4...137f90d674bc9";
    #endif
    
  • ResponseType:將 OIDC 處理常式設定為只執行授權碼流程。 在這個模式中,不需要隱含授與和混合式流程。

    在 Entra 或 Azure 入口網站的隱含授與和混合式流程應用程式註冊設定中,*請勿選取授權端點的核取方塊,以傳回 存取權杖識別碼權杖。 OIDC 處理常式使用從授權端點傳回的程式碼,自動要求適當的權杖。

    oidcOptions.ResponseType = OpenIdConnectResponseType.Code;
    
  • MapInboundClaimsNameClaimTypeRoleClaimType 的設定:許多 OIDC 伺服器在 ClaimTypes 使用 “name” 和 “role”,而不是使用 SOAP/WS-Fed 預設值。 MapInboundClaims 設定為 false 時,處理常式不會執行宣告對應,而且應用程式會直接使用 JWT 的宣告名稱。 下列範例會手動對應名稱和角色宣告:

注意

針對多數 OIDC 提供者,MapInboundClaims 必須設定為 false,以防重新命名宣告。

oidcOptions.MapInboundClaims = false;
oidcOptions.TokenValidationParameters.NameClaimType = JwtRegisteredClaimNames.Name;
oidcOptions.TokenValidationParameters.RoleClaimType = "role";
  • 路徑設定:路徑必須符合向 OIDC 提供者註冊應用程式時設定的重新導向 URI (登入回呼路徑),以及登出後重新導向 (登出回呼路徑)。 在 Azure 入口網站,路徑是在應用程式註冊的驗證刀鋒視窗設定。 登入和登出路徑都必須註冊為重新導向 URI。 預設值是 /signin-oidc/signout-callback-oidc

    • CallbackPath:應用程式基本路徑中傳回 user-agent 的要求路徑。

      在 Entra 或 Azure 入口網站,設定 Web 平台設定之重新導向 URI 的路徑:

      https://localhost/signin-oidc

      注意

      使用 Microsoft Entra ID 時,localhost 位址不需要連接埠。 其他 OIDC 提供者多半都需要正確的連接埠。

    • SignedOutCallbackPath:應用程式基本路徑中,登出識別提供者後傳回 user-agent 的要求路徑。

      在 Entra 或 Azure 入口網站,設定 Web 平台設定之重新導向 URI 的路徑:

      https://localhost/signout-callback-oidc

      注意

      使用 Microsoft Entra ID 時,localhost 位址不需要連接埠。 其他 OIDC 提供者多半都需要正確的連接埠。

      注意

      如果使用 Microsoft Identity Web,則提供者目前只會在使用 microsoftonline.com 授權單位 (https://login.microsoftonline.com/{TENANT ID}/v2.0/) 時重新導向回 SignedOutCallbackPath。 如果您可以搭配 Microsoft Identity Web 使用「通用」授權單位,則不存在這項限制。 如需詳細資訊,請參閱授權單位 url 包含租用戶識別碼 (AzureAD/microsoft-authentication-library-for-js #5783) 時 postLogoutRedirectUri 無法運作

    • RemoteSignOutPath:在這個路徑收到的要求導致處理常式使用登出配置叫用登出。

      在 Entra 或 Azure 入口網站,設定 Front-channel 登出 URL

      https://localhost/signout-oidc

      注意

      使用 Microsoft Entra ID 時,localhost 位址不需要連接埠。 其他 OIDC 提供者多半都需要正確的連接埠。

    oidcOptions.CallbackPath = new PathString("{PATH}");
    oidcOptions.SignedOutCallbackPath = new PathString("{PATH}");
    oidcOptions.RemoteSignOutPath = new PathString("{PATH}");
    

    範例 (預設值):

    oidcOptions.CallbackPath = new PathString("/signin-oidc");
    oidcOptions.SignedOutCallbackPath = new PathString("/signout-callback-oidc");
    oidcOptions.RemoteSignOutPath = new PathString("/signout-oidc");
    
  • (Microsoft Azure 僅使用「通用」端點) TokenValidationParameters.IssuerValidator:許多 OIDC 提供者會使用預設憑證簽發者驗證程式,但我們必須考慮以 https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration 傳回之租用戶標識碼 ({TENANT ID}) 參數化的憑證簽發者。 如需詳細資訊,請參閱 使用 OpenID Connect 與 Azure AD「通用」端點 (AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet #1731) 的 SecurityTokenInvalidIssuerException

    僅適用於使用 Microsoft Entra ID 或 Azure AD B2C 搭配「通用」端點的應用程式:

    var microsoftIssuerValidator = AadIssuerValidator.GetAadIssuerValidator(oidcOptions.Authority);
    oidcOptions.TokenValidationParameters.IssuerValidator = microsoftIssuerValidator.Validate;
    

應用程式範例的程式碼

檢查應用程式範例是否有下列功能:

  • 透過自訂 cookie 重新整理程式 (CookieOidcRefresher.cs) 協助的自動非互動式權杖重新整理。
  • PersistingAuthenticationStateProvider 類別 (PersistingAuthenticationStateProvider.cs) 是伺服器端 AuthenticationStateProvider,使用 PersistentComponentState 將驗證狀態流向用戶端,接著針對 WebAssembly 應用程式的存留期加以修正。
  • Program 檔案 (Program.cs) 中的最小 API 端點 (/weather-forecast) 會處理 Blazor Web 應用程式的天氣資料範例要求。 端點需要藉由呼叫 RequireAuthorization 來進行授權。 針對您新增至專案的任何控制器,請將 [Authorize] 屬性 新增至控制器或動作。
  • 這個應用程式在伺服器專案安全呼叫 (web) API 取得天氣資料:
    • 在伺服器轉譯 Weather 元件時,元件會使用伺服器上的 ServerWeatherForecaster 直接取得天氣資料 (而不是透過 Web API 呼叫)。
    • 在用戶端轉譯元件時,元件會使用 ClientWeatherForecaster 服務實作,它會使用預先設定的 HttpClient (位於用戶端專案的 Program 檔案) 對伺服器專案進行 Web API 呼叫。 伺服器專案 Program 檔案定義的最小 API 端點 (/weather-forecast),會從 ServerWeatherForecaster 取得天氣資料,並將資料傳回用戶端。

如需在 Blazor Web 應用程式使用服務抽象概念的 (web) API 呼叫詳細資訊,請參閱從 ASP.NET Core Blazor 應用程式呼叫 Web API

用戶端 Blazor Web 應用程式專案 (BlazorWebAppOidc.Client)

BlazorWebAppOidc.Client 專案是 Blazor Web 應用程式的用戶端專案。

PersistentAuthenticationStateProvider 類別 (PersistentAuthenticationStateProvider.cs) 是用戶端 AuthenticationStateProvider,藉由尋找在伺服器上轉譯時保存在頁面中的資料,判斷使用者的驗證狀態。 該驗證狀態已針對 WebAssembly 應用程式的存留期修正。

如果使用者需要登入或登出,則需要完整頁面重新載入。

應用程式範例提供使用者名稱和電子郵件僅供顯示之用。 不包含在提出後續要求時向伺服器驗證的權杖,而且是透過使用對伺服器提出之 HttpClient 要求中包含的 cookie 個別運作。

這個版本的發行項包含採用前端的後端 (BFF) 模式實作 OIDC。 如果應用程式的規格不要求採用 BFF 模式,請將發行項版本選取器變更為不使用 BFF 的 OIDC 模式

涵蓋下列規格:

  • Blazor Web 應用程式使用自動轉譯模式搭配全域互動
  • 伺服器和用戶端應用程式使用自訂驗證狀態提供者服務擷取使用者的驗證狀態,並在伺服器與客戶端之間流動。
  • 這個應用程式是任何 OIDC 驗證流程的起點。 OIDC 在應用程式手動設定,且不採用 Microsoft Entra IDMicrosoft Identity Web 套件,應用程式範例也不需要 Microsoft Azure 裝載。 不過,應用程式範例可與 Entra、Microsoft Identity Web 搭配使用,並且裝載於 Azure。
  • 自動非互動式權杖重新整理。
  • 採用前端的後端 (BFF) 模式,針對服務探索使用 .NET Aspire,而針對求在後端應用程式對天氣預報端點提出通過 Proxy 處理要求則是使用 YARP
    • 後端 Web API 使用 JWT 持有人驗證,驗證登入 cookie 中 Blazor Web 應用程式所儲存的 JWT 權杖。
    • Aspire 可改善建置 .NET 雲端原生應用程式的體驗。 它提供一組一致固定的工具和模式,用於建置和執行分散式應用程式。
    • YARP (又一個反向 Proxy) 是用來建立反向 Proxy 伺服器的程式庫。

預覽套件警告

警告

BlazorWebAppOidcBff 應用程式範例所使用的技術和套件,以及本文目前所述的預覽版本。 目前不支援本文的內容、API 和應用程式範例,目前不建議用於實際執行用途。 應用程式範例和指導隨時可能變更,恕不另行通知。

必要條件

.NET Aspire 需要 Visual Studio 17.10 版或更新版本。

範例應用程式

這個應用程式範例包含五個專案:

  • .NET Aspire:
    • Aspire.AppHost:用來管理應用程式的高階協調流程疑慮。
    • Aspire.ServiceDefaults:包含預設的 .NET Aspire 應用程式設定,該設定可視需要加以擴充及自訂。
  • MinimalApiJwt:後端 Web API,包含天氣資料的最小 API 端點範例。
  • BlazorWebAppOidc:Blazor Web 應用程式的伺服器端專案。
  • BlazorWebAppOidc.Client:Blazor Web 應用程式的用戶端專案。

請使用下列連結,透過存放庫根目錄中的最新版本資料夾存取應用程式範例。 專案位於 .NET 8 或更新版本的 BlazorWebAppOidcBff 資料夾。

檢視或下載範例程式碼 \(英文\) (如何下載)

.NET Aspire 專案

如需使用 .NET Aspire 的詳細資訊,以及應用程式範例 .AppHost.ServiceDefaults 專案的詳細資料,請參閱 .NET Aspire 文件

確認您已符合 .NET Aspire 的必要條件。 如需詳細資訊,請參閱 快速入門必要條件一節:建置您的第一個 .NET Aspire 應用程式

伺服器端 Blazor Web 應用程式專案 (BlazorWebAppOidc)

BlazorWebAppOidc 專案是 Blazor Web 應用程式的伺服器端專案。 專案會使用 YARP,將要求通過 Proxy 處理至後端 Web API 專案 (MinimalApiJwt) 中的氣象預報端點,並將 access_token 儲存於驗證 cookie 中。

BlazorWebAppOidc.http 檔案可用於測試天氣資料要求。 請注意,BlazorWebAppOidc 專案必須執行才能測試端點,而且端點會硬式編碼到檔案中。 如需詳細資訊,請參閱在 Visual Studio 2022 中使用 .http 檔案

注意

伺服器專案會使用 IHttpContextAccessor/HttpContext,但絕不會用於互動式轉譯的元件。 如需詳細資訊,請參閱 ASP.NET Core Blazor 互動式伺服器端轉譯的威脅風險降低指導

組態

本節說明如何設定應用程式範例。

注意

針對 Microsoft Entra ID 和 Azure AD B2C,您可以使用來自 Microsoft Identity WebAddMicrosoftIdentityWebApp (Microsoft.Identity.Web NuGet 套件API 文件),而且它同時會新增 OIDC 和具有適當預設值的 Cookie 驗證處理常式。 本節中的應用程式範例和指導不使用 Microsoft Identity Web。 這份指導示範如何為任何 OIDC 提供者手動設定 OIDC 處理常式。 如需實作 Microsoft Identity Web 的詳細資訊,請參閱連結的資源。

呼叫 AddOpenIdConnect 時,在專案的 Program 檔案找到下列 OpenIdConnectOptions設定:

  • SignInScheme:設定與在成功驗證後負責保存使用者身分識別之中介軟體對應的驗證配置。 OIDC 處理常式必須使用能夠跨要求保存使用者認證的登入配置。 下方這一行字僅供示範之用。 如果省略,則會使用 DefaultSignInScheme 做為備用值。

    oidcOptions.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    
  • openidprofile (Scope) 的範圍 (選擇性):預設也會設定 openidprofile 範圍,因為 OIDC 處理常式需要它們才能運作,但如果 Authentication:Schemes:MicrosoftOidc:Scope 設定包含範圍,則可能必須重新新增這些範圍。 如需一般設定指導,請參閱 ASP.NET Core 中的設定ASP.NET Core Blazor 設定

    oidcOptions.Scope.Add(OpenIdConnectScope.OpenIdProfile);
    
  • SaveTokens:定義了在成功授權之後,是否應該將存取和重新整理權杖儲存在 AuthenticationProperties 中。 值設定為 true,以驗證來自後端 Web API 專案 (MinimalApiJwt) 的天氣資料要求。

    oidcOptions.SaveTokens = true;
    
  • 離線存取的範圍 (Scope):重新整理權杖需要 offline_access 範圍。

    oidcOptions.Scope.Add(OpenIdConnectScope.OfflineAccess);
    
  • 從 Web API (Scope) 取得天氣資料的範圍:Weather.Get 範圍是在 Azure 或 Entra 入口網站的公開 API 下方設定。 後端 Web API 專案 (MinimalApiJwt) 必須執行此動作,才能使用持有人 JWT 驗證存取權杖。

    oidcOptions.Scope.Add("{APP ID URI}/{API NAME}");
    

    範例:

    • 應用程式識別碼 URI ({APP ID URI}):https://{DIRECTORY NAME}.onmicrosoft.com/{CLIENT ID}
      • 目錄名稱 ({DIRECTORY NAME}):contoso
      • 應用程式 (用戶端) 識別碼 ({CLIENT ID}):4ba4de56-9cef-45d9-83fa-a4c18f9f5f0f
    • 針對來自 MinimalApiJwt ({API NAME}) 之天氣資料所設定的範圍:Weather.Get
    oidcOptions.Scope.Add("https://contoso.onmicrosoft.com/4ba4de56-9cef-45d9-83fa-a4c18f9f5f0f/Weather.Get");
    

    上述範例是關於使用 AAD B2C 租用戶類型在租用戶註冊的應用程式。 如果應用程式已在 ME-ID 租用戶註冊,則 App ID URI 不同,因此範圍不同。

    範例:

    • App ID URI ({APP ID URI}):api://{CLIENT ID} 有應用程式 (用戶端) 識別碼 ({CLIENT ID}):4ba4de56-9cef-45d9-83fa-a4c18f9f5f0f
    • 針對來自 MinimalApiJwt ({API NAME}) 之天氣資料所設定的範圍:Weather.Get
    oidcOptions.Scope.Add("api://4ba4de56-9cef-45d9-83fa-a4c18f9f5f0f/Weather.Get");
    
  • AuthorityClientId:設定 OIDC 呼叫的授權單位和用戶端識別碼。

    oidcOptions.Authority = "{AUTHORITY}";
    oidcOptions.ClientId = "{CLIENT ID}";
    

    範例:

    • 授權單位 ({AUTHORITY}):https://login.microsoftonline.com/a3942615-d115-4eb7-bc84-9974abcf5064/v2.0/ (使用租用戶標識碼 a3942615-d115-4eb7-bc84-9974abcf5064)
    • 用戶端識別碼 ({CLIENT ID}):4ba4de56-9cef-45d9-83fa-a4c18f9f5f0f
    oidcOptions.Authority = "https://login.microsoftonline.com/a3942615-d115-4eb7-bc84-9974abcf5064/v2.0/";
    oidcOptions.ClientId = "4ba4de56-9cef-45d9-83fa-a4c18f9f5f0f";
    

    Microsoft Azure「通用」授權單位的範例:

    「通用」授權單位應該用於多租用戶應用程式。 您也可以針對單一租用戶應用程式使用「通用」授權單位,但需要有自訂的 IssuerValidator,如本節稍後所示。

    oidcOptions.Authority = "https://login.microsoftonline.com/common/v2.0/";
    
  • ClientSecret:OIDC 用戶端密碼。

    下列範例僅供測試與示範之用。 請勿將用戶端密碼儲存在應用程式的組件中,也不要將秘密提交到原始檔控制。 將用戶端密碼儲存於使用者祕密Azure Key Vault環境變數

    驗證配置設定會從 builder.Configuration["Authentication:Schemes:{SCHEME NAME}:{PropertyName}"] 自動讀取,其中 {SCHEME NAME} 預留位置是配置,預設為 MicrosoftOidc。 由於設定已預先設定,因此可以透過 Authentication:Schemes:MicrosoftOidc:ClientSecret 設定金鑰自動讀取用戶端密碼。 在使用環境變數的伺服器,將環境變數命名為 Authentication__Schemes__MicrosoftOidc__ClientSecret

    set Authentication__Schemes__MicrosoftOidc__ClientSecret={CLIENT SECRET}
    

    僅供示範和測試之用,可以直接設定 ClientSecret。 請勿為已部署的實際執行應用程式直接設定值。 為了稍微提升安全性,請以有條件的方式編譯DEBUG 符號的這行文字:

    #if DEBUG
    oidcOptions.ClientSecret = "{CLIENT SECRET}";
    #endif
    

    範例:

    用戶端密碼 ({CLIENT SECRET}):463471c8c4...f90d674bc9 (為顯示而縮短)

    #if DEBUG
    oidcOptions.ClientSecret = "463471c8c4...137f90d674bc9";
    #endif
    
  • ResponseType:將 OIDC 處理常式設定為只執行授權碼流程。 在這個模式中,不需要隱含授與和混合式流程。

    在 Entra 或 Azure 入口網站的隱含授與和混合式流程應用程式註冊設定中,*請勿選取授權端點的核取方塊,以傳回 存取權杖識別碼權杖。 OIDC 處理常式使用從授權端點傳回的程式碼,自動要求適當的權杖。

    oidcOptions.ResponseType = OpenIdConnectResponseType.Code;
    
  • MapInboundClaimsNameClaimTypeRoleClaimType 的設定:許多 OIDC 伺服器在 ClaimTypes 使用 “name” 和 “role”,而不是使用 SOAP/WS-Fed 預設值。 MapInboundClaims 設定為 false 時,處理常式不會執行宣告對應,而且應用程式會直接使用 JWT 的宣告名稱。 下列範例會手動對應名稱和角色宣告:

注意

針對多數 OIDC 提供者,MapInboundClaims 必須設定為 false,以防重新命名宣告。

oidcOptions.MapInboundClaims = false;
oidcOptions.TokenValidationParameters.NameClaimType = JwtRegisteredClaimNames.Name;
oidcOptions.TokenValidationParameters.RoleClaimType = "role";
  • 路徑設定:路徑必須符合向 OIDC 提供者註冊應用程式時設定的重新導向 URI (登入回呼路徑),以及登出後重新導向 (登出回呼路徑)。 在 Azure 入口網站,路徑是在應用程式註冊的驗證刀鋒視窗設定。 登入和登出路徑都必須註冊為重新導向 URI。 預設值是 /signin-oidc/signout-callback-oidc

    • CallbackPath:應用程式基本路徑中傳回 user-agent 的要求路徑。

      在 Entra 或 Azure 入口網站,設定 Web 平台設定之重新導向 URI 的路徑:

      https://localhost/signin-oidc

      注意

      localhost 位址不需要連接埠。

    • SignedOutCallbackPath:應用程式基本路徑中,登出識別提供者後傳回 user-agent 的要求路徑。

      在 Entra 或 Azure 入口網站,設定 Web 平台設定之重新導向 URI 的路徑:

      https://localhost/signout-callback-oidc

      注意

      localhost 位址不需要連接埠。

      注意

      如果使用 Microsoft Identity Web,則提供者目前只會在使用 microsoftonline.com 授權單位 (https://login.microsoftonline.com/{TENANT ID}/v2.0/) 時重新導向回 SignedOutCallbackPath。 如果您可以搭配 Microsoft Identity Web 使用「通用」授權單位,則不存在這項限制。 如需詳細資訊,請參閱授權單位 url 包含租用戶識別碼 (AzureAD/microsoft-authentication-library-for-js #5783) 時 postLogoutRedirectUri 無法運作

    • RemoteSignOutPath:在這個路徑收到的要求導致處理常式使用登出配置叫用登出。

      在 Entra 或 Azure 入口網站,設定 Front-channel 登出 URL

      https://localhost/signout-oidc

      注意

      localhost 位址不需要連接埠。

    oidcOptions.CallbackPath = new PathString("{PATH}");
    oidcOptions.SignedOutCallbackPath = new PathString("{PATH}");
    oidcOptions.RemoteSignOutPath = new PathString("{PATH}");
    

    範例 (預設值):

    oidcOptions.CallbackPath = new PathString("/signin-oidc");
    oidcOptions.SignedOutCallbackPath = new PathString("/signout-callback-oidc");
    oidcOptions.RemoteSignOutPath = new PathString("/signout-oidc");
    
  • (Microsoft Azure 僅使用「通用」端點) TokenValidationParameters.IssuerValidator:許多 OIDC 提供者會使用預設憑證簽發者驗證程式,但我們必須考慮以 https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration 傳回之租用戶標識碼 ({TENANT ID}) 參數化的憑證簽發者。 如需詳細資訊,請參閱 使用 OpenID Connect 與 Azure AD「通用」端點 (AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet #1731) 的 SecurityTokenInvalidIssuerException

    僅適用於使用 Microsoft Entra ID 或 Azure AD B2C 搭配「通用」端點的應用程式:

    var microsoftIssuerValidator = AadIssuerValidator.GetAadIssuerValidator(oidcOptions.Authority);
    oidcOptions.TokenValidationParameters.IssuerValidator = microsoftIssuerValidator.Validate;
    

應用程式範例的程式碼

檢查應用程式範例是否有下列功能:

  • 透過自訂 cookie 重新整理程式 (CookieOidcRefresher.cs) 協助的自動非互動式權杖重新整理。
  • PersistingAuthenticationStateProvider 類別 (PersistingAuthenticationStateProvider.cs) 是伺服器端 AuthenticationStateProvider,使用 PersistentComponentState 將驗證狀態流向用戶端,接著針對 WebAssembly 應用程式的存留期加以修正。
  • 對 Blazor Web 應用程式的要求會由 Proxy 處理至後端 Web API 專案 (MinimalApiJwt)。 Program 檔案中的 MapForwarder 使用傳出要求的預設設定、自訂的轉換和預設 HTTP 用戶端,將符合指定模式的 HTTP 要求直接轉送至特定目的地:
    • 在伺服器轉譯 Weather 元件時,元件使用 ServerWeatherForecaster 通過 Proxy 處理天氣資料的要求與使用者的存取權杖。
    • 在用戶端轉譯元件時,元件會使用 ClientWeatherForecaster 服務實作,它會使用預先設定的 HttpClient (位於用戶端專案的 Program 檔案) 對伺服器專案進行 Web API 呼叫。 伺服器專案 Program 檔案中定義的最小 API 端點 (/weather-forecast),使用使用者的存取權杖轉換要求,取得天氣資料。

如需在 Blazor Web 應用程式使用服務抽象概念的 (web) API 呼叫詳細資訊,請參閱從 ASP.NET Core Blazor 應用程式呼叫 Web API

用戶端 Blazor Web 應用程式專案 (BlazorWebAppOidc.Client)

BlazorWebAppOidc.Client 專案是 Blazor Web 應用程式的用戶端專案。

PersistentAuthenticationStateProvider 類別 (PersistentAuthenticationStateProvider.cs) 是用戶端 AuthenticationStateProvider,藉由尋找在伺服器上轉譯時保存在頁面中的資料,判斷使用者的驗證狀態。 該驗證狀態已針對 WebAssembly 應用程式的存留期修正。

如果使用者需要登入或登出,則需要完整頁面重新載入。

應用程式範例提供使用者名稱和電子郵件僅供顯示之用。 不包含在提出後續要求時向伺服器驗證的權杖,而且是透過使用對伺服器提出之 HttpClient 要求中包含的 cookie 個別運作。

後端 Web API 專案 (MinimalApiJwt)

MinimalApiJwt 專案是多個前端專案的後端 Web API。 專案會為天氣資料設定最小 API 端點。 來自 Blazor Web 應用程式伺服器端專案 (BlazorWebAppOidc) 的要求會通過 Proxy 處理至 MinimalApiJwt 專案。

組態

在專案的 Program 檔案中,於 AddJwtBearer 呼叫的 JwtBearerOptions 設定專案:

  • Audience:設定任何已接收 OpenID Connect 權杖的受眾。

    在 Azure 或 Entra 入口網站:將值與在 [公開 API]下方新增 Weather.Get 範圍時所設定之應用程式識別碼 URI 的路徑比對:

    jwtOptions.Audience = "{APP ID URI}";
    

    範例:

    應用程式識別碼 URI ({APP ID URI}):https://{DIRECTORY NAME}.onmicrosoft.com/{CLIENT ID}

    • 目錄名稱 ({DIRECTORY NAME}):contoso
    • 應用程式 (用戶端) 識別碼 ({CLIENT ID}):4ba4de56-9cef-45d9-83fa-a4c18f9f5f0f
    jwtOptions.Audience = "https://contoso.onmicrosoft.com/4ba4de56-9cef-45d9-83fa-a4c18f9f5f0f";
    

    上述範例是關於使用 AAD B2C 租用戶類型在租用戶註冊的應用程式。 如果應用程式已在 ME-ID 租用戶註冊,則 App ID URI 不同,因此受眾不同。

    範例:

    App ID URI ({APP ID URI}):api://{CLIENT ID} 有應用程式 (用戶端) 識別碼 ({CLIENT ID}):4ba4de56-9cef-45d9-83fa-a4c18f9f5f0f

    jwtOptions.Audience = "api://4ba4de56-9cef-45d9-83fa-a4c18f9f5f0f";
    
  • Authority:設定進行 OpenID Connect 呼叫的授權單位。 將值與 BlazorWebAppOidc/Program.cs 中為 OIDC 處理常式設定的授權單位比對:

    jwtOptions.Authority = "{AUTHORITY}";
    

    範例:

    授權單位 ({AUTHORITY}):https://login.microsoftonline.com/a3942615-d115-4eb7-bc84-9974abcf5064/v2.0/ (使用租用戶標識碼 a3942615-d115-4eb7-bc84-9974abcf5064)

    jwtOptions.Authority = "https://login.microsoftonline.com/a3942615-d115-4eb7-bc84-9974abcf5064/v2.0/";
    

    上述範例是關於使用 AAD B2C 租用戶類型在租用戶註冊的應用程式。 如果應用程式已在 ME-ID 租用戶註冊,授權單位應該與識別提供者所傳回之 JWT 的憑證簽發者 (iss) 相符:

    jwtOptions.Authority = "https://sts.windows.net/a3942615-d115-4eb7-bc84-9974abcf5064/";
    

天氣資料的最小 API

保護專案 Program 檔案中的天氣預報資料端點:

app.MapGet("/weather-forecast", () =>
{
    var forecast = 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();
    return forecast;
}).RequireAuthorization();

RequireAuthorization 擴充方法需要路由定義的授權。 針對您新增至專案的任何控制器,請將 [Authorize] 屬性 新增至控制器或動作。

登出時重新導向至首頁

使用者瀏覽應用程式時,LogInOrOut 元件 (Layout/LogInOrOut.razor) 會將傳回 URL (ReturnUrl) 的隱藏欄位設定為目前 URL (currentURL) 的值。 使用者登出應用程式時,識別提供者會讓他們返回登出時的頁面。

如果使用者從安全頁面登出,則只有在登出後,才會透過驗證流程返回相同的安全頁面。 使用者需要經常切換帳戶時,這個行為完全沒問題。 不過,替代的應用程式規格可能會要求使用者,在登出後返回應用程式的首頁或其他頁面。 下列範例示範如何將應用程式的首頁設定為登出作業的返回 URL。

下列範例示範 LogInOrOut 元件的重要變更。 ReturnUrl 隱藏欄位的 value 會設定為位於 /的首頁。 已不再實作 IDisposable。 已不再插入 NavigationManager。 已移除整個 @code 區塊。

Layout/LogInOrOut.razor

@using Microsoft.AspNetCore.Authorization

<div class="nav-item px-3">
    <AuthorizeView>
        <Authorized>
            <form action="authentication/logout" method="post">
                <AntiforgeryToken />
                <input type="hidden" name="ReturnUrl" value="/" />
                <button type="submit" class="nav-link">
                    <span class="bi bi-arrow-bar-left-nav-menu" aria-hidden="true">
                    </span> Logout @context.User.Identity?.Name
                </button>
            </form>
        </Authorized>
        <NotAuthorized>
            <a class="nav-link" href="authentication/login">
                <span class="bi bi-person-badge-nav-menu" aria-hidden="true"></span> 
                Login
            </a>
        </NotAuthorized>
    </AuthorizeView>
</div>

密碼編譯 nonce

nonce 是字串值,將用戶端的工作階段與識別碼權杖產生關聯,以緩和重新執行攻擊

如果您在驗證開發和測試期間收到 nonce 錯誤,無論對應用程式或測試使用者所做的變更有多小,都請針對每個測試回合使用新的 InPrivate/無痕瀏覽模式瀏覽器工作階段,因為過時的 cookie 資料可能導致 nonce 錯誤。 如需詳細資訊,請參閱Cookie 與網站資料 一節。

重新整理權杖換取新的存取權杖時,不需要也不會使用 nonce。 在應用程式範例中,CookieOidcRefresher (CookieOidcRefresher.cs) 刻意將 OpenIdConnectProtocolValidator.RequireNonce 設定為 false

疑難排解

記錄

伺服器應用程式是標準 ASP.NET Core 應用程式。 請參閱 ASP.NET Core 記錄指導,在伺服器應用程式啟用較低的記錄層級。

若要啟用 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 或伺服器應用程式會傳回錯誤訊息或有導致問題的線索訊息給用戶端。 下列文章中可找到開發人員工具指導:

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

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

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

  • 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 套件總管

執行伺服器應用程式

測試 Blazor Web 應用程式並且進行疑難排解時,請確定您是從伺服器專案執行應用程式。

檢查使用者

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

UserClaims.razor

@page "/user-claims"
@using System.Security.Claims
@using Microsoft.AspNetCore.Authorization
@attribute [Authorize]

<PageTitle>User Claims</PageTitle>

<h1>User Claims</h1>

@if (claims.Count() > 0)
{
    <ul>
        @foreach (var claim in claims)
        {
            <li><b>@claim.Type:</b> @claim.Value</li>
        }
    </ul>
}

@code {
    private IEnumerable<Claim> claims = Enumerable.Empty<Claim>();

    [CascadingParameter]
    private Task<AuthenticationState>? AuthState { get; set; }

    protected override async Task OnInitializedAsync()
    {
        if (AuthState == null)
        {
            return;
        }

        var authState = await AuthState;
        claims = authState.User.Claims;
    }
}

其他資源