Udostępnij za pomocą


Zabezpiecz ASP.NET Core Blazor Web App za pomocą Microsoft Entra ID

W tym artykule opisano sposób zabezpieczania Blazor Web Appza pomocą platformy tożsamości firmy Microsoft z pakietami Identity microsoft Web dla identyfikatora Entra firmy Microsoft przy użyciu przykładowej aplikacji.

W tej wersji artykułu opisano implementację Entra bez przyjmowania wzorca Backend for Frontend (BFF). Wzorzec BFF jest przydatny do podejmowania uwierzytelnionych żądań do usług zewnętrznych. Zmień selektor wersji artykułu na wzorzec BFF , jeśli specyfikacja aplikacji wywołuje wdrożenie wzorca BFF.

Opisano następującą specyfikację:

  • Funkcja Blazor Web App używa trybu automatycznego renderowania z globalną interakcyjnością (InteractiveAuto).
  • Projekt serwera wywołuje AddAuthenticationStateSerialization, aby dodać dostawcę stanu uwierzytelniania po stronie serwera, który używa PersistentComponentState do przekazywania stanu uwierzytelniania do klienta. Klient wywołuje AddAuthenticationStateDeserialization w celu deserializacji i użycia stanu uwierzytelniania przekazanego przez serwer. Stan uwierzytelniania jest stały dla okresu istnienia aplikacji WebAssembly.
  • Aplikacja używa identyfikatora Entra firmy Microsoft opartego na pakietach microsoft Identity Web .
  • Automatyczne odświeżanie tokenów nieinterakcyjnych jest zarządzane przez platformę.
  • Aplikacja używa abstrakcji usługi po stronie serwera i po stronie klienta do wyświetlania wygenerowanych danych pogodowych:
    • Podczas renderowania Weather składnika na serwerze w celu wyświetlenia danych pogodowych składnik używa elementu ServerWeatherForecaster. Pakiety sieci Web firmy Microsoft Identity udostępniają interfejs API do tworzenia nazwanej podrzędnej usługi webowej umożliwiającej wywołania API sieci Web. IDownstreamApi jest wstrzykiwany do ServerWeatherForecaster, który służy do wywoływania CallApiForUserAsync w celu uzyskania danych pogodowych z zewnętrznego interfejsu API projektu MinimalApiJwt.
    • Gdy składnik Weather jest renderowany na kliencie, używa ClientWeatherForecaster implementacji usługi, która korzysta z wstępnie skonfigurowanego HttpClient (w pliku projektu Program klienta) do wykonania wywołania sieciowego API do Minimalnego interfejsu API serwera (/weather-forecast) w celu uzyskania danych pogodowych. Minimalny punkt końcowy interfejsu API uzyskuje dane pogodowe z ServerWeatherForecaster klasy i zwraca je do klienta do renderowania przez składnik.

Przykładowe rozwiązanie

Przykładowe rozwiązanie składa się z następujących projektów:

  • BlazorWebAppEntra: Projekt po stronie serwera Blazor Web App, zawierający przykładowy punkt końcowy dla Minimalnego API danych pogodowych.
  • BlazorWebAppEntra.Client: implementacja po stronie klienta komponentu Blazor Web App.
  • MinimalApiJwt: internetowy interfejs API zaplecza zawierający przykładowy minimalny punkt końcowy interfejsu API dla danych pogodowych.

Dostęp do przykładu za pośrednictwem najnowszego folderu wersji w repozytorium przykładów Blazor za pomocą następującego linku. Przykład znajduje się w folderze BlazorWebAppEntra dla platformy .NET 9 lub nowszej.

Uruchom rozwiązanie z Aspire/Aspire.AppHost projektu.

Wyświetlanie lub pobieranie przykładowego kodu (jak pobrać)

Rejestracje aplikacji Microsoft Entra ID

Zalecamy używanie oddzielnych rejestracji dla aplikacji i internetowych interfejsów API, nawet jeśli aplikacje i internetowe interfejsy API znajdują się w tym samym rozwiązaniu. Poniższe wskazówki dotyczą aplikacji BlazorWebAppEntra i interfejsów API MinimalApiJwt internetowych przykładowego rozwiązania, ale te same wskazówki ogólnie dotyczą wszystkich rejestracji bazujących na usłudze Entra dla aplikacji i interfejsów API internetowych.

Najpierw zarejestruj internetowy interfejs API (MinimalApiJwt), aby można było udzielić dostępu do internetowego interfejsu API podczas rejestrowania aplikacji. Identyfikator dzierżawy i identyfikator klienta internetowego interfejsu API służą do konfigurowania internetowego interfejsu API w jego Program pliku. Po zarejestrowaniu internetowego interfejsu API, eksponuj internetowy interfejs API w rejestracjach aplikacji>Eksponowanie interfejsu API przy użyciu nazwy Weather.Get zakresu. Zapisz URI identyfikatora aplikacji do użycia w konfiguracji aplikacji.

Następnie zarejestruj aplikację (BlazorWebAppEntra) przy użyciu konfiguracji platformy internetowej z dwoma wpisami w obszarze Identyfikator URI przekierowania: https://localhost/signin-oidc i https://localhost/signout-callback-oidc (porty nie są wymagane w tych identyfikatorach URI). Ustaw adres URL wylogowywania kanału frontowego na https://localhost/signout-callback-oidc (port nie jest wymagany). Identyfikator dzierżawcy aplikacji, domena dzierżawy i identyfikator klienta, wraz z bazowym adresem internetowego interfejsu API, URI Identyfikatora Aplikacji i nazwą zakresu danych pogodowych, są wykorzystywane do konfigurowania aplikacji w pliku appsettings.json. Przyznaj uprawnienia interfejsu API do uzyskania dostępu do internetowego interfejsu API w rejestracji aplikacji>Uprawnienia interfejsu API. Jeśli specyfikacja zabezpieczeń aplikacji wywołuje to żądanie, możesz udzielić organizacji zgody administratora w celu uzyskania dostępu do internetowego interfejsu API. Autoryzowani użytkownicy i grupy są przypisywani do rejestracji aplikacji w aplikacjach> dlaprzedsiębiorstw.

W konfiguracji rejestracji aplikacji w portalu Entra lub Azure, w sekcji Niejawne nadania uprawnień i przepływy hybrydowe, nie zaznaczaj pól wyboru dla punktu końcowego autoryzacji w celu zwrócenia tokenów dostępu lub tokenów ID. Procedura obsługi OpenID Connect automatycznie żąda odpowiednich tokenów przy użyciu kodu zwróconego z punktu końcowego autoryzacji.

Utwórz tajny klienta w ramach rejestracji aplikacji w portalu Entra lub Azure (Zarządzaj>Certyfikaty i tajne informacje>Nowy tajny klienta). Trzymaj w tajemnicy wartość klienta do użycia w następnej sekcji.

Dodatkowe wskazówki dotyczące konfiguracji entra dla określonych ustawień podano w dalszej części tego artykułu.

Projekt po stronie Blazor Web App serwera (BlazorWebAppEntra)

Projekt BlazorWebAppEntra jest projektem po stronie serwera programu Blazor Web App.

Projekt po stronie klienta Blazor Web AppBlazorWebAppEntra.Client

Projekt BlazorWebAppEntra.Client jest projektem po stronie klienta programu Blazor Web App.

Jeśli użytkownik musi się zalogować lub wylogować podczas renderowania po stronie klienta, zostanie zainicjowane ponowne załadowanie pełnej strony.

Projekt webowego backendowego interfejsu API (MinimalApiJwt)

Projekt MinimalApiJwt jest backendowym API dla wielu projektów frontendowych. Projekt konfiguruje minimalny punkt końcowy interfejsu API dla danych pogodowych.

Plik MinimalApiJwt.http może służyć do testowania żądania danych pogodowych. Należy pamiętać, że MinimalApiJwt projekt musi być uruchomiony, aby przetestować punkt końcowy, a punkt końcowy jest zakodowany w pliku. Aby uzyskać więcej informacji, zobacz Use .http files in Visual Studio 2022 (Używanie plików HTTP w programie Visual Studio 2022).

Projekt zawiera pakiety i konfigurację do tworzenia dokumentów OpenAPI.

Bezpieczny punkt końcowy danych prognozy pogody znajduje się w pliku projektu 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();

Metoda RequireAuthorization rozszerzenia wymaga autoryzacji dla definicji trasy. W przypadku wszystkich kontrolerów dodanych do projektu dodaj [Authorize] atrybut do kontrolera lub akcji.

Skonfiguruj projekt zaplecza serwerowego interfejsu API (MinimalApiJwt)

Skonfiguruj projekt w JwtBearerOptions w ramach wywołania AddJwtBearer w pliku MinimalApiJwt projektu Program.

W przypadku rejestracji Weather.Get aplikacji internetowego interfejsu API zakres jest skonfigurowany w portalu Entra lub Azure w sekcji Ujawnij interfejs API.

Authority konfiguruje autorytet do wykonywania wywołań OIDC.

jwtOptions.Authority = "{AUTHORITY}";

W poniższych przykładach użyto identyfikatora dzierżawy aaaabbbb-0000-cccc-1111-dddd2222eeee i nazwy contoso katalogu.

Jeśli aplikacja jest zarejestrowana w dzierżawie ME-ID, autorytet powinien być zgodny z wydawcą (iss) tokenu JWT zwróconego przez dostawcę tożsamości.

jwtOptions.Authority = "https://sts.windows.net/aaaabbbb-0000-cccc-1111-dddd2222eeee";

Jeśli aplikacja jest zarejestrowana w dzierżawie Microsoft Entra External ID:

jwtOptions.Authority = "https://contoso.ciamlogin.com/aaaabbbb-0000-cccc-1111-dddd2222eeee/v2.0";

Jeśli aplikacja jest zarejestrowana w koncie usługi AAD B2C:

jwtOptions.Authority = "https://login.microsoftonline.com/aaaabbbb-0000-cccc-1111-dddd2222eeee/v2.0";

Note

Usługa Azure Active Directory B2C nie jest już dostępna jako usługa dla nowych klientów od 1 maja 2025 r. Dzierżawy AAD B2C są obsługiwane dla klientów, którzy utworzyli konta przed 1 maja 2025 r., do roku 2030. Aby uzyskać więcej informacji, zobacz Azure AD B2C: często zadawane pytania.

Audience Ustawia grupę odbiorców dla dowolnego odebranego tokenu dostępu JWT.

jwtOptions.Audience = "{AUDIENCE}";

Dopasuj wartość tylko do ścieżki URI identyfikatora aplikacji skonfigurowanego podczas dodawania Weather.Get zakresu w obszarze Wystaw interfejs API w portalu Entra lub Azure. Nie uwzględniaj nazwy zakresu „Weather.Get” w wartości.

W poniższych przykładach użyto identyfikatora aplikacji (klienta) .11112222-bbbb-3333-cccc-4444dddd5555 W trzecim przykładzie użyto domeny najemcy contoso.onmicrosoft.com.

przykład dzierżawy ME-ID:

jwtOptions.Audience = "api://11112222-bbbb-3333-cccc-4444dddd5555";

Dzierżawa Microsoft Entra External ID:

jwtOptions.Audience = "11112222-bbbb-3333-cccc-4444dddd5555";

Przykład dzierżawcy usługi AAD B2C (Azure Active Directory B2C):

jwtOptions.Audience = "https://contoso.onmicrosoft.com/11112222-bbbb-3333-cccc-4444dddd5555";

Konfigurowanie projektu serwera (BlazorWebAppEntra)

AddMicrosoftIdentityWebAppz Microsoft Identity Web (Microsoft.Identity.Webpakiet NuGet, dokumentacja API) jest skonfigurowany w pliku projektu.

Uzyskaj identyfikator aplikacji (klienta), domenę dzierżawy (wydawcy) i identyfikator katalogu (dzierżawy) z rejestracji aplikacji w portalu Entra lub Azure. Identyfikator URI aplikacji jest uzyskiwany dla Weather.Get zakresu z rejestracji interfejsu API. Nie dołączaj nazwy zakresu podczas pobierania identyfikatora URI aplikacji z portalu.

Konfiguracja uwierzytelniania zależy od typu dzierżawy:

konfiguracja klienta ME-ID

Ta sekcja dotyczy aplikacji zarejestrowanej w usłudze Microsoft Entra ID lub dzierżawie usługi Azure AAD B2C.

BlazorWebAppEntra W pliku projektu Program podaj wartości następujących symboli zastępczych w konfiguracji sieci Web firmy MicrosoftIdentity:

builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApp(msIdentityOptions =>
    {
        msIdentityOptions.CallbackPath = "/signin-oidc";
        msIdentityOptions.ClientId = "{CLIENT ID (BLAZOR APP)}";
        msIdentityOptions.Domain = "{DIRECTORY NAME}.onmicrosoft.com";
        msIdentityOptions.Instance = "https://login.microsoftonline.com/";
        msIdentityOptions.ResponseType = "code";
        msIdentityOptions.TenantId = "{TENANT ID}";
    })
    .EnableTokenAcquisitionToCallDownstreamApi()
    .AddDownstreamApi("DownstreamApi", configOptions =>
    {
        configOptions.BaseUrl = "{BASE ADDRESS}";
        configOptions.Scopes = ["{APP ID URI}/Weather.Get"];
    })
    .AddDistributedTokenCaches();

Symbole zastępcze w poprzedniej konfiguracji:

  • {CLIENT ID (BLAZOR APP)}: identyfikator aplikacji (klienta).
  • {DIRECTORY NAME}: nazwa katalogowa domeny najemcy (wydawcy).
  • {TENANT ID}: identyfikator katalogu (najemcy).
  • {BASE ADDRESS}: podstawowy adres internetowego interfejsu API.
  • {APP ID URI}: URI identyfikatora aplikacji dla zakresów interfejsu API sieci Web. Jeden z następujących formatów jest używany, gdzie symbol {CLIENT ID (WEB API)} jest identyfikatorem klienta rejestracji webowego interfejsu API Entra, a symbol {DIRECTORY NAME} jest nazwą katalogu domeny dzierżawcy (wydawcy) (na przykład: contoso).
    • ME-ID format dzierżawy: api://{CLIENT ID (WEB API)}
    • Format dzierżawy B2C: https://{DIRECTORY NAME}.onmicrosoft.com/{CLIENT ID (WEB API)}

Example:

builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApp(msIdentityOptions =>
    {
        msIdentityOptions.CallbackPath = "/signin-oidc";
        msIdentityOptions.ClientId = "00001111-aaaa-2222-bbbb-3333cccc4444";
        msIdentityOptions.Domain = "contoso.onmicrosoft.com";
        msIdentityOptions.Instance = "https://login.microsoftonline.com/";
        msIdentityOptions.ResponseType = "code";
        msIdentityOptions.TenantId = "aaaabbbb-0000-cccc-1111-dddd2222eeee";
    })
    .EnableTokenAcquisitionToCallDownstreamApi()
    .AddDownstreamApi("DownstreamApi", configOptions =>
    {
        configOptions.BaseUrl = "https://localhost:7277";
        configOptions.Scopes = ["api://11112222-bbbb-3333-cccc-4444dddd5555/Weather.Get"];
    })
    .AddDistributedTokenCaches();

Konfiguracja identyfikatora zewnętrznego firmy Microsoft Entra

Ta sekcja dotyczy aplikacji zarejestrowanej w dzierżawie Microsoft Entra External ID.

BlazorWebAppEntra W pliku projektu Program podaj wartości następujących symboli zastępczych w konfiguracji sieci Web firmy MicrosoftIdentity:

builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApp(msIdentityOptions =>
    {
        msIdentityOptions.CallbackPath = "/signin-oidc";
        msIdentityOptions.Authority = "https://{DIRECTORY NAME}.ciamlogin.com/{TENANT ID}/v2.0";
        msIdentityOptions.ClientId = "{CLIENT ID (BLAZOR APP)}";
        msIdentityOptions.ResponseType = "code";
    })
    .EnableTokenAcquisitionToCallDownstreamApi()
    .AddDownstreamApi("DownstreamApi", configOptions =>
    {
        configOptions.BaseUrl = "{BASE ADDRESS}";
        configOptions.Scopes = ["{APP ID URI}/Weather.Get"];
    })
    .AddDistributedTokenCaches();

Symbole zastępcze w poprzedniej konfiguracji:

  • {DIRECTORY NAME}: nazwa katalogowa domeny najemcy (wydawcy).
  • {CLIENT ID (BLAZOR APP)}: identyfikator aplikacji (klienta).
  • {BASE ADDRESS}: podstawowy adres internetowego interfejsu API.
  • {APP ID URI}: URI identyfikatora aplikacji dla zakresów interfejsu API sieci Web. Jeden z następujących formatów jest używany, gdzie {CLIENT ID (WEB API)} placeholder jest identyfikatorem klienta rejestracji Entra dla internetowego interfejsu API, a {DIRECTORY NAME} placeholder oznacza nazwę katalogową domeny najemcy (wydawcy) (na przykład: contoso).
    • Format dzierżawy ME-ID lub Microsoft Entra External ID: api://{CLIENT ID (WEB API)}
    • Format dzierżawy B2C: https://{DIRECTORY NAME}.onmicrosoft.com/{CLIENT ID (WEB API)}

Example:

builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApp(msIdentityOptions =>
    {
        msIdentityOptions.CallbackPath = "/signin-oidc";
        msIdentityOptions.Authority = "https://contoso.ciamlogin.com/aaaabbbb-0000-cccc-1111-dddd2222eeee/v2.0";
        msIdentityOptions.ClientId = "00001111-aaaa-2222-bbbb-3333cccc4444";
        msIdentityOptions.ResponseType = "code";
    })
    .EnableTokenAcquisitionToCallDownstreamApi()
    .AddDownstreamApi("DownstreamApi", configOptions =>
    {
        configOptions.BaseUrl = "https://localhost:7277";
        configOptions.Scopes = ["api://11112222-bbbb-3333-cccc-4444dddd5555/Weather.Get"];
    })
    .AddDistributedTokenCaches();

Ścieżka wywołania zwrotnego (CallbackPath) musi być zgodna z URI przekierowania (ścieżka wywołania zwrotnego logowania) skonfigurowanym podczas rejestrowania aplikacji w portalu Entra lub Azure. Ścieżki są konfigurowane w sekcji Uwierzytelnianie podczas rejestracji aplikacji. Domyślna wartość CallbackPath to /signin-oidc dla zarejestrowanego przekierowania URI https://localhost/signin-oidc (port nie jest wymagany).

SignedOutCallbackPath to ścieżka żądania w podstawowej ścieżce aplikacji przechwytywana przez mechanizm obsługi OpenID Connect, w którym agent użytkownika jest najpierw zwracany po wylogowaniu z Entra. Przykładowa aplikacja nie ustawia wartości dla ścieżki, ponieważ jest używana domyślna wartość "/signout-callback-oidc". Po przechwyceniu żądania program obsługi OpenID Connect przekierowuje do „SignedOutRedirectUri” lub „RedirectUri”, jeśli określono.

Warning

Nie przechowuj tajnych danych aplikacji, parametrów połączenia, danych uwierzytelniających, haseł, osobistych numerów identyfikacyjnych (PIN), prywatnego kodu C#/.NET lub kluczy prywatnych/tokenów w kodzie po stronie klienta, który zawsze jest niezabezpieczony. W środowiskach testowych/przejściowych i produkcyjnych kod po stronie Blazor serwera i internetowe interfejsy API powinny używać bezpiecznych przepływów uwierzytelniania, które unikają utrzymywania poświadczeń w kodzie projektu lub plikach konfiguracji. Poza lokalnymi testami programistycznymi zalecamy unikanie używania zmiennych środowiskowych do przechowywania poufnych danych, ponieważ zmienne środowiskowe nie są najbezpieczniejszym podejściem. W przypadku lokalnego testowania programistycznego narzędzie Secret Manager jest zalecane do zabezpieczania poufnych danych. Aby uzyskać więcej informacji, zobacz Bezpieczne utrzymywanie poufnych danych i poświadczeń.

W tej wersji artykułu opisano implementację Entra z użyciem wzorca Backend for Frontend (BFF). Zmień selektor wersji artykułu na Wzorzec inny niż BFF , jeśli specyfikacja aplikacji nie wywołuje wdrożenia wzorca BFF.

Opisano następującą specyfikację:

  • Funkcja Blazor Web App używa trybu automatycznego renderowania z globalną interakcyjnością (InteractiveAuto).
  • Projekt serwera wywołuje AddAuthenticationStateSerialization, aby dodać dostawcę stanu uwierzytelniania po stronie serwera, który używa PersistentComponentState do przekazywania stanu uwierzytelniania do klienta. Klient wywołuje AddAuthenticationStateDeserialization w celu deserializacji i użycia stanu uwierzytelniania przekazanego przez serwer. Stan uwierzytelniania jest stały dla okresu istnienia aplikacji WebAssembly.
  • Aplikacja używa identyfikatora Entra firmy Microsoft opartego na pakietach microsoft Identity Web .
  • Automatyczne odświeżanie tokenów nieinterakcyjnych jest zarządzane przez platformę.
  • Wzorzec Backend for Frontend (BFF) jest przyjęty, używając Aspire do odkrywania usług i YARP do proxy żądań do punktu końcowego prognozy pogody w aplikacji zaplecza.
    • Zaplecze internetowe API używa uwierzytelniania jako posiadacz JWT do weryfikacji tokenów JWT zapisanych przez Blazor Web App podczas logowania cookie.
    • Aspire usprawnia tworzenie aplikacji natywnych dla chmury platformy .NET. Zapewnia spójny, opiniowany zestaw narzędzi i wzorców do tworzenia i uruchamiania aplikacji rozproszonych.
    • YARP (Jeszcze inny zwrotny serwer proxy) to biblioteka używana do tworzenia zwrotnego serwera proxy.
  • Aplikacja używa abstrakcji usługi po stronie serwera i po stronie klienta do wyświetlania wygenerowanych danych pogodowych.
    • Podczas renderowania Weather składnika na serwerze w celu wyświetlenia danych pogodowych składnik używa elementu ServerWeatherForecaster. Pakiety sieci Web firmy Microsoft Identity udostępniają interfejs API do tworzenia nazwanej podrzędnej usługi webowej umożliwiającej wywołania API sieci Web. IDownstreamApi jest wstrzykiwany do ServerWeatherForecaster, który służy do wywoływania CallApiForUserAsync w celu uzyskania danych pogodowych z zewnętrznego interfejsu API projektu MinimalApiJwt.
    • Gdy składnik Weather jest renderowany na kliencie, używa ClientWeatherForecaster implementacji usługi, która korzysta z wstępnie skonfigurowanego HttpClient (w pliku projektu Program klienta) do wykonania wywołania sieciowego API do Minimalnego interfejsu API serwera (/weather-forecast) w celu uzyskania danych pogodowych. Minimalny punkt końcowy interfejsu API uzyskuje token dostępu dla użytkownika przez wywołanie metody GetAccessTokenForUserAsync. Razem z prawidłowymi zakresami, wywołanie serwera proxy typu reverse jest wykonywane do zewnętrznego internetowego interfejsu API projektu (MinimalApiJwt), aby uzyskać dane pogodowe i zwrócić je klientowi do renderowania przez składnik.

Prerequisites

Aspire program Wymaga programu Visual Studio w wersji 17.10 lub nowszej.

Zobacz również sekcję Wymagania wstępne w przewodniku Szybki start: tworzenie pierwszego Aspire rozwiązania.

Przykładowe rozwiązanie

Przykładowe rozwiązanie składa się z następujących projektów:

  • Aspire:
    • Aspire.AppHost: służy do zarządzania ogólnymi problemami dotyczącymi aranżacji aplikacji.
    • Aspire.ServiceDefaults: zawiera domyślne Aspire konfiguracje aplikacji, które można rozszerzyć i dostosować zgodnie z potrzebami.
  • MinimalApiJwt: internetowy interfejs API zaplecza zawierający przykładowy minimalny punkt końcowy interfejsu API dla danych pogodowych.
  • BlazorWebAppEntra: Projekt po stronie serwera programu Blazor Web App.
  • BlazorWebAppEntra.Client: implementacja po stronie klienta komponentu Blazor Web App.

Dostęp do przykładu za pośrednictwem najnowszego folderu wersji w repozytorium przykładów Blazor za pomocą następującego linku. Przykład znajduje się w folderze BlazorWebAppEntraBff dla platformy .NET 9 lub nowszej.

Wyświetlanie lub pobieranie przykładowego kodu (jak pobrać)

Rejestracje aplikacji Microsoft Entra ID

Zalecamy używanie oddzielnych rejestracji dla aplikacji i internetowych interfejsów API, nawet jeśli aplikacje i internetowe interfejsy API znajdują się w tym samym rozwiązaniu. Poniższe wskazówki dotyczą aplikacji BlazorWebAppEntra i interfejsów API MinimalApiJwt internetowych przykładowego rozwiązania, ale te same wskazówki ogólnie dotyczą wszystkich rejestracji bazujących na usłudze Entra dla aplikacji i interfejsów API internetowych.

Najpierw zarejestruj internetowy interfejs API (MinimalApiJwt), aby można było udzielić dostępu do internetowego interfejsu API podczas rejestrowania aplikacji. Identyfikator dzierżawy i identyfikator klienta internetowego interfejsu API służą do konfigurowania internetowego interfejsu API w jego Program pliku. Po zarejestrowaniu internetowego interfejsu API, eksponuj internetowy interfejs API w rejestracjach aplikacji>Eksponowanie interfejsu API przy użyciu nazwy Weather.Get zakresu. Zapisz URI identyfikatora aplikacji do użycia w konfiguracji aplikacji.

Następnie zarejestruj aplikację (BlazorWebAppEntra) przy użyciu konfiguracji platformy internetowej z dwoma wpisami w obszarze Identyfikator URI przekierowania: https://localhost/signin-oidc i https://localhost/signout-callback-oidc (porty nie są wymagane w tych identyfikatorach URI). Identyfikator dzierżawcy aplikacji, domena dzierżawy i identyfikator klienta, wraz z bazowym adresem internetowego interfejsu API, URI Identyfikatora Aplikacji i nazwą zakresu danych pogodowych, są wykorzystywane do konfigurowania aplikacji w pliku appsettings.json. Przyznaj uprawnienia interfejsu API do uzyskania dostępu do internetowego interfejsu API w rejestracji aplikacji>Uprawnienia interfejsu API. Jeśli specyfikacja zabezpieczeń aplikacji wywołuje to żądanie, możesz udzielić organizacji zgody administratora w celu uzyskania dostępu do internetowego interfejsu API. Autoryzowani użytkownicy i grupy są przypisywani do rejestracji aplikacji w aplikacjach> dlaprzedsiębiorstw.

W konfiguracji rejestracji aplikacji w portalu Entra lub Azure, w sekcji Niejawne nadania uprawnień i przepływy hybrydowe, nie zaznaczaj pól wyboru dla punktu końcowego autoryzacji w celu zwrócenia tokenów dostępu lub tokenów ID. Procedura obsługi OpenID Connect automatycznie żąda odpowiednich tokenów przy użyciu kodu zwróconego z punktu końcowego autoryzacji.

Utwórz tajny klienta w ramach rejestracji aplikacji w portalu Entra lub Azure (Zarządzaj>Certyfikaty i tajne informacje>Nowy tajny klienta). Trzymaj w tajemnicy wartość klienta do użycia w następnej sekcji.

Dodatkowe wskazówki dotyczące konfiguracji entra dla określonych ustawień podano w dalszej części tego artykułu.

Projekty: Aspire

Aby uzyskać więcej informacji na temat korzystania z Aspire oraz szczegóły dotyczące projektów .AppHost i .ServiceDefaults w przykładowej aplikacji, zobacz dokumentację Aspire.

Upewnij się, że zostały spełnione wymagania wstępne dotyczące programu Aspire. Aby uzyskać więcej informacji, zobacz sekcję Wymagania wstępne przewodnika Szybki start: tworzenie pierwszego Aspire rozwiązania.

Przykładowa aplikacja konfiguruje tylko niezabezpieczony profil uruchamiania HTTP (http) do użycia podczas testowania programistycznego. Aby uzyskać więcej informacji, w tym przykład niezabezpieczonych i bezpiecznych profilów ustawień uruchamiania, zobacz Zezwalanie na niezabezpieczony transport w Aspire (Aspire dokumentacja).

Projekt po stronie Blazor Web App serwera (BlazorWebAppEntra)

Projekt BlazorWebAppEntra jest projektem po stronie serwera programu Blazor Web App.

Projekt po stronie klienta Blazor Web AppBlazorWebAppEntra.Client

Projekt BlazorWebAppEntra.Client jest projektem po stronie klienta programu Blazor Web App.

Jeśli użytkownik musi się zalogować lub wylogować podczas renderowania po stronie klienta, zostanie zainicjowane ponowne załadowanie pełnej strony.

Projekt webowego backendowego interfejsu API (MinimalApiJwt)

Projekt MinimalApiJwt jest backendowym API dla wielu projektów frontendowych. Projekt konfiguruje minimalny punkt końcowy interfejsu API dla danych pogodowych. Żądania z Blazor Web App projektu po stronie serwera (BlazorWebAppEntra) są kierowane do MinimalApiJwt projektu.

Plik MinimalApiJwt.http może służyć do testowania żądania danych pogodowych. Należy pamiętać, że MinimalApiJwt projekt musi być uruchomiony, aby przetestować punkt końcowy, a punkt końcowy jest zakodowany w pliku. Aby uzyskać więcej informacji, zobacz Use .http files in Visual Studio 2022 (Używanie plików HTTP w programie Visual Studio 2022).

Projekt zawiera pakiety i konfigurację do tworzenia dokumentów OpenAPI.

Bezpieczny punkt końcowy danych prognozy pogody znajduje się w pliku projektu 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();

Metoda RequireAuthorization rozszerzenia wymaga autoryzacji dla definicji trasy. W przypadku wszystkich kontrolerów dodanych do projektu dodaj [Authorize] atrybut do kontrolera lub akcji.

Skonfiguruj projekt zaplecza serwerowego interfejsu API (MinimalApiJwt)

Skonfiguruj projekt MinimalApiJwt w wywołaniu JwtBearerOptions w pliku AddJwtBearer projektu Program.

W przypadku rejestracji Weather.Get aplikacji internetowego interfejsu API zakres jest skonfigurowany w portalu Entra lub Azure w sekcji Ujawnij interfejs API.

Authority konfiguruje autorytet do wykonywania wywołań OIDC.

jwtOptions.Authority = "{AUTHORITY}";

W poniższych przykładach użyto identyfikatora dzierżawy aaaabbbb-0000-cccc-1111-dddd2222eeee i nazwy katalogu contoso.

Jeśli aplikacja jest zarejestrowana w dzierżawie ME-ID, autorytet powinien być zgodny z wydawcą (iss) tokenu JWT zwróconego przez dostawcę tożsamości.

jwtOptions.Authority = "https://sts.windows.net/aaaabbbb-0000-cccc-1111-dddd2222eeee";

Jeśli aplikacja jest zarejestrowana w dzierżawie identyfikatora zewnętrznego Microsoft Entra:

jwtOptions.Authority = "https://contoso.ciamlogin.com/aaaabbbb-0000-cccc-1111-dddd2222eeee/v2.0";

Jeśli aplikacja jest zarejestrowana w koncie usługi AAD B2C:

jwtOptions.Authority = "https://login.microsoftonline.com/aaaabbbb-0000-cccc-1111-dddd2222eeee/v2.0";

Note

Usługa Azure Active Directory B2C nie jest już dostępna jako usługa dla nowych klientów od 1 maja 2025 r. Dzierżawcy usługi AAD B2C są obsługiwani dla klientów z kontami utworzonymi przed 1 maja 2025 r., aż do 2030 r. Aby uzyskać więcej informacji, zobacz Azure AD B2C: często zadawane pytania.

Audience Ustawia grupę odbiorców dla dowolnego odebranego tokenu dostępu JWT.

jwtOptions.Audience = "{AUDIENCE}";

Dopasuj wartość tylko do ścieżki URI identyfikatora aplikacji skonfigurowanego podczas dodawania Weather.Get zakresu w obszarze Wystaw interfejs API w portalu Entra lub Azure. Nie uwzględniaj nazwy zakresu „Weather.Get” w wartości.

W poniższych przykładach użyto identyfikatora aplikacji (klienta) .11112222-bbbb-3333-cccc-4444dddd5555 W trzecim przykładzie użyto domeny dzierżawcy contoso.onmicrosoft.com.

przykład dzierżawy ME-ID:

jwtOptions.Audience = "api://11112222-bbbb-3333-cccc-4444dddd5555";

Microsoft Entra External ID tenant:

jwtOptions.Audience = "11112222-bbbb-3333-cccc-4444dddd5555";

Przykład dzierżawcy usługi AAD B2C (Azure Active Directory B2C):

jwtOptions.Audience = "https://contoso.onmicrosoft.com/11112222-bbbb-3333-cccc-4444dddd5555";

Konfigurowanie projektu serwera (BlazorWebAppEntra)

AddMicrosoftIdentityWebAppz Microsoft Identity Web (Microsoft.Identity.Webpakiet NuGet, dokumentacja API) jest skonfigurowany w pliku projektu.

Uzyskaj identyfikator aplikacji (klienta), domenę dzierżawy (wydawcy) i identyfikator katalogu (dzierżawy) z rejestracji aplikacji w portalu Entra lub Azure. Identyfikator URI aplikacji jest uzyskiwany dla Weather.Get zakresu z rejestracji interfejsu API. Nie dołączaj nazwy zakresu podczas pobierania identyfikatora URI aplikacji z portalu.

Konfiguracja uwierzytelniania zależy od typu dzierżawy:

konfiguracja dzierżawy ME-ID

Ta sekcja dotyczy aplikacji zarejestrowanej w usłudze Microsoft Entra ID lub dzierżawie usługi Azure AAD B2C.

BlazorWebAppEntra W pliku projektu Program podaj wartości następujących symboli zastępczych w konfiguracji sieci Web firmy MicrosoftIdentity:

builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApp(msIdentityOptions =>
    {
        msIdentityOptions.CallbackPath = "/signin-oidc";
        msIdentityOptions.ClientId = "{CLIENT ID (BLAZOR APP)}";
        msIdentityOptions.Domain = "{DIRECTORY NAME}.onmicrosoft.com";
        msIdentityOptions.Instance = "https://login.microsoftonline.com/";
        msIdentityOptions.ResponseType = "code";
        msIdentityOptions.TenantId = "{TENANT ID}";
    })
    .EnableTokenAcquisitionToCallDownstreamApi()
    .AddDownstreamApi("DownstreamApi", configOptions =>
    {
        configOptions.BaseUrl = "{BASE ADDRESS}";
        configOptions.Scopes = ["{APP ID URI}/Weather.Get"];
    })
    .AddDistributedTokenCaches();

Podaj ten sam zakres podrzędnego interfejsu API do przekształcania żądań:

List<string> scopes = ["{APP ID URI}/Weather.Get"];

Symbole zastępcze w poprzedniej konfiguracji:

  • {CLIENT ID (BLAZOR APP)}: identyfikator aplikacji (klienta).
  • {DIRECTORY NAME}: nazwa katalogowa domeny najemcy (wydawcy).
  • {TENANT ID}: identyfikator katalogu (najemcy).
  • {BASE ADDRESS}: podstawowy adres internetowego interfejsu API.
  • {APP ID URI}: URI identyfikatora aplikacji dla zakresów interfejsu API sieci Web. Jeden z następujących formatów jest używany, gdzie symbol {CLIENT ID (WEB API)} jest identyfikatorem klienta rejestracji webowego interfejsu API Entra, a symbol {DIRECTORY NAME} jest nazwą katalogu domeny dzierżawcy (wydawcy) (na przykład: contoso).
    • ME-ID format dzierżawy: api://{CLIENT ID (WEB API)}
    • Format dzierżawy B2C: https://{DIRECTORY NAME}.onmicrosoft.com/{CLIENT ID (WEB API)}

Example:

builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApp(msIdentityOptions =>
    {
        msIdentityOptions.CallbackPath = "/signin-oidc";
        msIdentityOptions.ClientId = "00001111-aaaa-2222-bbbb-3333cccc4444";
        msIdentityOptions.Domain = "contoso.onmicrosoft.com";
        msIdentityOptions.Instance = "https://login.microsoftonline.com/";
        msIdentityOptions.ResponseType = "code";
        msIdentityOptions.TenantId = "aaaabbbb-0000-cccc-1111-dddd2222eeee";
    })
    .EnableTokenAcquisitionToCallDownstreamApi()
    .AddDownstreamApi("DownstreamApi", configOptions =>
    {
        configOptions.BaseUrl = "https://localhost:7277";
        configOptions.Scopes = 
            ["api://11112222-bbbb-3333-cccc-4444dddd5555/Weather.Get"];
    })
    .AddDistributedTokenCaches();

Example:

List<string> scopes = ["api://11112222-bbbb-3333-cccc-4444dddd5555/Weather.Get"];

Konfiguracja identyfikatora zewnętrznego firmy Microsoft Entra

Ta sekcja dotyczy aplikacji zarejestrowanej w dzierżawie Microsoft Entra External ID.

BlazorWebAppEntra W pliku projektu Program podaj wartości następujących symboli zastępczych w konfiguracji sieci Web firmy MicrosoftIdentity:

builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApp(msIdentityOptions =>
    {
        msIdentityOptions.CallbackPath = "/signin-oidc";
        msIdentityOptions.Authority = "https://{DIRECTORY NAME}.ciamlogin.com/{TENANT ID}/v2.0";
        msIdentityOptions.ClientId = "{CLIENT ID (BLAZOR APP)}";
        msIdentityOptions.ResponseType = "code";
    })
    .EnableTokenAcquisitionToCallDownstreamApi()
    .AddDownstreamApi("DownstreamApi", configOptions =>
    {
        configOptions.BaseUrl = "{BASE ADDRESS}";
        configOptions.Scopes = ["{APP ID URI}/Weather.Get"];
    })
    .AddDistributedTokenCaches();

Podaj ten sam zakres podrzędnego interfejsu API do przekształcania żądań:

List<string> scopes = ["{APP ID URI}/Weather.Get"];

Symbole zastępcze w poprzedniej konfiguracji:

  • {DIRECTORY NAME}: nazwa katalogowa domeny najemcy (wydawcy).
  • {CLIENT ID (BLAZOR APP)}: identyfikator aplikacji (klienta).
  • {BASE ADDRESS}: podstawowy adres internetowego interfejsu API.
  • {APP ID URI}: URI identyfikatora aplikacji dla zakresów interfejsu API sieci Web. Jeden z następujących formatów jest używany, gdzie symbol {CLIENT ID (WEB API)} jest identyfikatorem klienta rejestracji webowego interfejsu API Entra, a symbol {DIRECTORY NAME} jest nazwą katalogu domeny dzierżawcy (wydawcy) (na przykład: contoso).
    • Format identyfikatora zewnętrznego Microsoft Entra lub ME-ID: api://{CLIENT ID (WEB API)}
    • Format dzierżawy B2C: https://{DIRECTORY NAME}.onmicrosoft.com/{CLIENT ID (WEB API)}

Example:

builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApp(msIdentityOptions =>
    {
        msIdentityOptions.CallbackPath = "/signin-oidc";
        msIdentityOptions.Authority = "https://contoso.ciamlogin.com/aaaabbbb-0000-cccc-1111-dddd2222eeee/v2.0";
        msIdentityOptions.ClientId = "00001111-aaaa-2222-bbbb-3333cccc4444";
        msIdentityOptions.ResponseType = "code";
    })
    .EnableTokenAcquisitionToCallDownstreamApi()
    .AddDownstreamApi("DownstreamApi", configOptions =>
    {
        configOptions.BaseUrl = "https://localhost:7277";
        configOptions.Scopes = ["api://11112222-bbbb-3333-cccc-4444dddd5555/Weather.Get"];
    })
    .AddDistributedTokenCaches();

Example:

List<string> scopes = ["api://11112222-bbbb-3333-cccc-4444dddd5555/Weather.Get"];

Warning

Aplikacje produkcyjne powinny używać produkcyjnego dostawcy rozproszonej pamięci podręcznej tokenów. W przeciwnym razie aplikacja może mieć niską wydajność w niektórych scenariuszach. Aby uzyskać więcej informacji, zobacz sekcję Use a production distributed token cache provider (Używanie produkcyjnego dostawcy rozproszonej pamięci podręcznej tokenów ).

Ścieżka wywołania zwrotnego (CallbackPath) musi być zgodna z URI przekierowania (ścieżka wywołania zwrotnego logowania) skonfigurowanym podczas rejestrowania aplikacji w portalu Entra lub Azure. Ścieżki są konfigurowane w sekcji Uwierzytelnianie podczas rejestracji aplikacji. Domyślna wartość CallbackPath to /signin-oidc dla zarejestrowanego przekierowania URI https://localhost/signin-oidc (port nie jest wymagany).

SignedOutCallbackPath to ścieżka żądania w podstawowej ścieżce aplikacji przechwytywana przez mechanizm obsługi OpenID Connect, w którym agent użytkownika jest najpierw zwracany po wylogowaniu z Entra. Przykładowa aplikacja nie ustawia wartości dla ścieżki, ponieważ jest używana domyślna wartość "/signout-callback-oidc". Po przechwyceniu żądania program obsługi OpenID Connect przekierowuje do „SignedOutRedirectUri” lub „RedirectUri”, jeśli określono.

Warning

Nie przechowuj tajnych danych aplikacji, parametrów połączenia, danych uwierzytelniających, haseł, osobistych numerów identyfikacyjnych (PIN), prywatnego kodu C#/.NET lub kluczy prywatnych/tokenów w kodzie po stronie klienta, który zawsze jest niezabezpieczony. W środowiskach testowych/przejściowych i produkcyjnych kod po stronie Blazor serwera i internetowe interfejsy API powinny używać bezpiecznych przepływów uwierzytelniania, które unikają utrzymywania poświadczeń w kodzie projektu lub plikach konfiguracji. Poza lokalnymi testami programistycznymi zalecamy unikanie używania zmiennych środowiskowych do przechowywania poufnych danych, ponieważ zmienne środowiskowe nie są najbezpieczniejszym podejściem. W przypadku lokalnego testowania programistycznego narzędzie Secret Manager jest zalecane do zabezpieczania poufnych danych. Aby uzyskać więcej informacji, zobacz Bezpieczne utrzymywanie poufnych danych i poświadczeń.

Ustal tajny klucz klienta

Ta sekcja dotyczy tylko projektu serwera programu Blazor Web App.

Użyj jednej lub obu następujących metod, aby podać klucz tajny klienta do aplikacji:

  • Narzędzie Secret Manager: narzędzie Secret Manager przechowuje prywatne dane na komputerze lokalnym i jest używane tylko podczas programowania lokalnego.
  • Azure Key Vault: klucz tajny klienta można przechowywać w magazynie kluczy do użycia w dowolnym środowisku, w tym dla środowiska deweloperskiego podczas pracy lokalnie. Niektórzy deweloperzy wolą używać magazynów kluczy do wdrażania przejściowego i produkcyjnego oraz używać narzędzia Secret Manager do programowania lokalnego.

Zdecydowanie zalecamy unikanie przechowywania wpisów tajnych klienta w kodzie projektu lub plikach konfiguracji. Użyj bezpiecznych przepływów uwierzytelniania, takich jak jeden lub oba podejścia opisane w tej sekcji.

Narzędzie Secret Manager

Narzędzie Secret Manager może przechowywać klucz tajny klienta aplikacji serwera pod kluczem konfiguracji AzureAd:ClientSecret.

Aplikacja Blazor serwera nie została zainicjowana dla narzędzia Secret Manager. Użyj skorupki poleceń, takiej jak skorupka PowerShell dla deweloperów w programie Visual Studio, aby wykonać następujące polecenie. Przed wykonaniem polecenia zmień katalog poleceniem cd na katalog projektu serwera. Polecenie ustanawia identyfikator tajemnic użytkownika (<UserSecretsId>) w pliku projektu aplikacji serwerowej, który jest używany wewnętrznie przez narzędzia do śledzenia tajemnic aplikacji.

dotnet user-secrets init

Wykonaj następujące polecenie, aby ustawić klucz tajny klienta. Symbol zastępczy {SECRET} to klucz tajny klienta uzyskany z rejestracji aplikacji w systemie Entra.

dotnet user-secrets set "AzureAd:ClientSecret" "{SECRET}"

Jeśli używasz programu Visual Studio, możesz potwierdzić, że wpis tajny został ustawiony, klikając prawym przyciskiem myszy projekt serwera w Eksploratorze rozwiązań i wybierając polecenie Zarządzaj wpisami tajnymi użytkownika.

Azure Key Vault

Usługa Azure Key Vault zapewnia bezpieczne podejście do udostępniania tajemnicy klienta aplikacji dla aplikacji.

Aby utworzyć magazyn kluczy i ustawić tajny klucz klienta, zobacz Informacje o wpisach tajnych usługi Azure Key Vault (dokumentacja platformy Azure), w których połączone są zasoby do rozpoczęcia pracy z usługą Azure Key Vault. Aby zaimplementować kod w tej sekcji, zapisz identyfikator URI magazynu kluczy i nazwę tajemnicy z Azure, podczas tworzenia magazynu kluczy i tajemnicy. W przykładzie w tej sekcji nazwa wpisu tajnego to "BlazorWebAppEntraClientSecret".

Podczas tworzenia magazynu kluczy w portalu Entra lub Azure:

  • Skonfiguruj magazyn kluczy do używania kontroli dostępu opartej na rolach (RABC) platformy Azure. Jeśli nie korzystasz z usługi Azure Virtual Network, w tym na potrzeby lokalnego programowania i testowania, upewnij się, że dostęp publiczny w kroku Sieć jest włączony (zaznaczone). Włączenie dostępu publicznego uwidacznia tylko punkt końcowy magazynu kluczy. Uwierzytelnione konta są nadal wymagane do uzyskania dostępu.

  • Utwórz zarządzaną tożsamość Azure Identity (lub dodaj rolę do istniejącej zarządzanej tożsamości Identity, której zamierzasz użyć) z rolą Użytkownik tajemnic Key Vault. Przypisz Managed Identity do usługi Azure App Service, która hostuje wdrożenie: Ustawienia>Identity>Przypisane przez użytkownika>Dodaj.

    Note

    Jeśli planujesz również lokalnie uruchomić aplikację z autoryzowanym użytkownikiem mającym dostęp do magazynu kluczy przy użyciu Azure CLI lub uwierzytelniania usługi Azure w programie Visual Studio, dodaj konto użytkownika platformy Azure dewelopera w obszarze Kontrola dostępu (IAM) z rolą Użytkownika sekretów magazynu kluczy. Jeśli chcesz użyć Azure CLI za pośrednictwem programu Visual Studio, wykonaj polecenie az login z panelu Developer PowerShell i postępuj zgodnie z monitami, aby się uwierzytelnić w dzierżawie.

Aby zaimplementować kod w tej sekcji, zapisz identyfikator URI magazynu kluczy (na przykład: "https://contoso.vault.azure.net/", wymagany ukośnik na końcu) i nazwę tajemnicy (przykład: "BlazorWebAppEntraClientSecret") z platformy Azure przy tworzeniu magazynu kluczy i tajemnicy.

Important

Tajemnica magazynu kluczy jest tworzona z datą wygaśnięcia. Pamiętaj, aby śledzić, kiedy tajemnica w magazynie kluczy wygaśnie, i utworzyć nową tajemnicę dla aplikacji przed upływem tej daty.

Dodaj następującą klasę AzureHelper do projektu serwera. Metoda GetKeyVaultSecret pobiera sekret ze skarbca kluczy. Dostosuj przestrzeń nazw (BlazorSample.Helpers), aby pasować do schematu przestrzeni nazw projektu.

Helpers/AzureHelper.cs:

using Azure.Core;
using Azure.Security.KeyVault.Secrets;

namespace BlazorWebAppEntra.Helpers;

public static class AzureHelper
{
    public static string GetKeyVaultSecret(string vaultUri, 
        TokenCredential credential, string secretName)
    {
        var client = new SecretClient(new Uri(vaultUri), credential);
        var secret = client.GetSecretAsync(secretName).Result;

        return secret.Value.Value;
    }
}

Note

W poprzednim przykładzie użyto DefaultAzureCredential metody upraszczania uwierzytelniania podczas opracowywania aplikacji wdrażanych na platformie Azure przez połączenie poświadczeń używanych w środowiskach hostingu platformy Azure z poświadczeniami używanymi podczas programowania lokalnego. Podczas przechodzenia do środowiska produkcyjnego lepszym wyborem jest alternatywa, taka jak ManagedIdentityCredential. Aby uzyskać więcej informacji, zobacz Uwierzytelnianie aplikacji platformy .NET hostowanych na platformie Azure do zasobów platformy Azure przy użyciu tożsamości zarządzanej przypisanej przez system.

Gdzie usługi są zarejestrowane w pliku projektu Program serwera, uzyskaj i zastosuj klucz tajny klienta przy użyciu następującego kodu:

TokenCredential? credential;

if (builder.Environment.IsProduction())
{
    credential = new ManagedIdentityCredential("{MANAGED IDENTITY CLIENT ID}");
}
else
{
    // Local development and testing only
    DefaultAzureCredentialOptions options = new()
    {
        // Specify the tenant ID to use the dev credentials when running the app locally
        // in Visual Studio.
        VisualStudioTenantId = "{TENANT ID}",
        SharedTokenCacheTenantId = "{TENANT ID}"
    };

    credential = new DefaultAzureCredential(options);
}

Gdzie MicrosoftIdentityOptions są ustawione, wywołaj metodę GetKeyVaultSecret , aby odbierać i przypisywać klucz tajny klienta aplikacji:

msIdentityOptions.ClientSecret = AzureHelper.GetKeyVaultSecret("{VAULT URI}", 
    credential, "{SECRET NAME}");

{MANAGED IDENTITY CLIENT ID}: identyfikator klienta zarządzanego Identity platformy Azure (GUID).

{TENANT ID}: identyfikator katalogu (najemcy). Przykład: aaaabbbb-0000-cccc-1111-dddd2222eeee

{VAULT URI}: adres URI magazynu kluczy. Dodaj ukośnik na końcu identyfikatora URI. Przykład: https://contoso.vault.azure.net/

{SECRET NAME}: tajna nazwa. Przykład: BlazorWebAppEntraClientSecret

Konfiguracja umożliwia dostarczanie dedykowanych magazynów kluczy i nazw sekretów na podstawie plików konfiguracji środowiskowej aplikacji. Na przykład można podać różne wartości konfiguracji dla appsettings.Development.json w środowisku deweloperskim, appsettings.Staging.json w środowisku testowym i appsettings.Production.json dla wdrożenia produkcyjnego. Aby uzyskać więcej informacji, zobacz konfigurację ASP.NET Core.

Serializacja tylko nazw i twierdzeń dotyczących roli

Program W pliku wszystkie oświadczenia są serializowane przez ustawienie SerializeAllClaims na true. Jeśli chcesz, aby dla żądania CSR były serializowane tylko nazwa i oświadczenia dotyczące roli, usuń opcję lub ustaw to na false.

Podaj konfigurację za pomocą dostawcy konfiguracji JSON (ustawienia aplikacyjne)

Przykładowe projekty rozwiązań konfigurują uwierzytelnianie Microsoft Web i za pomocą JWT bearer w swoich Identity plikach, aby umożliwić łatwe odnajdywanie ustawień konfiguracji przy użyciu autouzupełniania języka C#. Aplikacje profesjonalne zwykle używają dostawcy konfiguracji do konfigurowania opcji OIDC, takich jak domyślny dostawca konfiguracji JSON. Dostawca konfiguracji JSON ładuje konfigurację z plików ustawień aplikacji appsettings.json/appsettings.{ENVIRONMENT}.json, gdzie placeholder {ENVIRONMENT} to środowisko uruchomieniowe aplikacji. Postępuj zgodnie ze wskazówkami w tej sekcji, aby użyć plików ustawień aplikacji do konfiguracji.

W pliku ustawień aplikacji (appsettings.json) BlazorWebAppEntra projektu dodaj następującą konfigurację JSON:

{
  "AzureAd": {
    "CallbackPath": "/signin-oidc",
    "ClientId": "{CLIENT ID (BLAZOR APP)}",
    "Domain": "{DIRECTORY NAME}.onmicrosoft.com",
    "Instance": "https://login.microsoftonline.com/",
    "ResponseType": "code",
    "TenantId": "{TENANT ID}"
  },
  "DownstreamApi": {
    "BaseUrl": "{BASE ADDRESS}",
    "Scopes": ["{APP ID URI}/Weather.Get"]
  }
}

Zaktualizuj symbole zastępcze w poprzedniej konfiguracji, aby odpowiadały wartościom, które aplikacja używa w pliku Program.

  • {CLIENT ID (BLAZOR APP)}: identyfikator aplikacji (klienta).
  • {DIRECTORY NAME}: nazwa katalogowa domeny najemcy (wydawcy).
  • {TENANT ID}: identyfikator katalogu (najemcy).
  • {BASE ADDRESS}: podstawowy adres internetowego interfejsu API.
  • {APP ID URI}: URI identyfikatora aplikacji dla zakresów interfejsu API sieci Web. Jeden z następujących formatów jest używany, gdzie symbol {CLIENT ID (WEB API)} jest identyfikatorem klienta rejestracji webowego interfejsu API Entra, a symbol {DIRECTORY NAME} jest nazwą katalogu domeny dzierżawcy (wydawcy) (na przykład: contoso).
    • ME-ID format dzierżawy: api://{CLIENT ID (WEB API)}
    • Format dzierżawy B2C: https://{DIRECTORY NAME}.onmicrosoft.com/{CLIENT ID (WEB API)}

Example:

"AzureAd": {
  "CallbackPath": "/signin-oidc",
  "ClientId": "00001111-aaaa-2222-bbbb-3333cccc4444",
  "Domain": "contoso.onmicrosoft.com",
  "Instance": "https://login.microsoftonline.com/",
  "ResponseType": "code",
  "TenantId": "aaaabbbb-0000-cccc-1111-dddd2222eeee"
},
"DownstreamApi": {
  "BaseUrl": "https://localhost:7277",
  "Scopes": ["api://11112222-bbbb-3333-cccc-4444dddd5555/Weather.Get"]
}

Zaktualizuj wszystkie inne wartości w poprzedniej konfiguracji, aby odpowiadały wartościom niestandardowym/innym niż domyślne używane w Program pliku.

Konfiguracja jest automatycznie pobierana przez konstruktora uwierzytelniania.

Wprowadź następujące zmiany w Program pliku:

builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
-   .AddMicrosoftIdentityWebApp(msIdentityOptions =>
-   {
-       msIdentityOptions.CallbackPath = "...";
-       msIdentityOptions.ClientId = "...";
-       msIdentityOptions.Domain = "...";
-       msIdentityOptions.Instance = "...";
-       msIdentityOptions.ResponseType = "...";
-       msIdentityOptions.TenantId = "...";
-   })
+   .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"))
    .EnableTokenAcquisitionToCallDownstreamApi()
-   .AddDownstreamApi("DownstreamApi", configOptions =>
-   {
-       configOptions.BaseUrl = "...";
-       configOptions.Scopes = ["..."];
-   })
+   .AddDownstreamApi("DownstreamApi", builder.Configuration.GetSection("DownstreamApi"))
    .AddDistributedTokenCaches();
- List<string> scopes = ["{APP ID URI}/Weather.Get"];
- var accessToken = await tokenAcquisition.GetAccessTokenForUserAsync(scopes);
+ var configuration = transformContext.HttpContext.RequestServices.GetRequiredService<IConfiguration>();
+ var scopes = configuration.GetSection("DownstreamApi:Scopes").Get<IEnumerable<string>>();
+ var accessToken = await tokenAcquisition.GetAccessTokenForUserAsync(scopes ??
+     throw new InvalidOperationException("No downstream API scopes!"));

Note

Aplikacje produkcyjne powinny używać produkcyjnego dostawcy rozproszonej pamięci podręcznej tokenów. W przeciwnym razie aplikacja może mieć niską wydajność w niektórych scenariuszach. Aby uzyskać więcej informacji, zobacz sekcję Use a production distributed token cache provider (Używanie produkcyjnego dostawcy rozproszonej pamięci podręcznej tokenów ).

W projekcie MinimalApiJwt dodaj następującą konfigurację ustawień aplikacji do appsettings.json pliku:

"Authentication": {
  "Schemes": {
    "Bearer": {
      "Authority": "https://sts.windows.net/{TENANT ID (WEB API)}",
      "ValidAudiences": ["{APP ID URI (WEB API)}"]
    }
  }
},

Zaktualizuj symbole zastępcze w poprzedniej konfiguracji, aby odpowiadały wartościom, które aplikacja używa w pliku Program.

  • {TENANT ID (WEB API)}: identyfikator Tenant Id interfejsu API.
  • {APP ID URI (WEB API)}: Identyfikator URI interfejsu API aplikacji sieciowej.

Formaty autorytetu przyjmują następujące wzorce:

  • ME-ID typ najemcy: https://sts.windows.net/{TENANT ID}
  • Identyfikator zewnętrzny firmy Microsoft: https://{DIRECTORY NAME}.ciamlogin.com/{TENANT ID}/v2.0
  • Typ dzierżawy B2C: https://login.microsoftonline.com/{TENANT ID}/v2.0

Formaty odbiorców przyjmują następujące wzorce ({CLIENT ID} to identyfikator klienta internetowego interfejsu API; {DIRECTORY NAME} to nazwa katalogu, na przykład contoso):

  • ME-ID typ najemcy: api://{CLIENT ID}
  • Identyfikator zewnętrzny firmy Microsoft: {CLIENT ID}
  • Typ dzierżawy B2C: https://{DIRECTORY NAME}.onmicrosoft.com/{CLIENT ID}

Konfiguracja jest automatycznie pobierana przez konstruktora uwierzytelniania elementu nośnego JWT.

Usuń następujące wiersze z Program pliku:

- jwtOptions.Authority = "...";
- jwtOptions.Audience = "...";

Aby uzyskać więcej informacji na temat konfiguracji, zobacz następujące zasoby:

Korzystanie z produkcyjnego dostawcy rozproszonej pamięci podręcznej tokenów

Rozproszone buforowanie tokenów w pamięci jest tworzone po wywołaniu AddDistributedTokenCaches, aby zapewnić dostępność podstawowej implementacji buforowania tokenów rozproszonych.

Produkcyjne aplikacje internetowe i internetowe interfejsy API powinny używać produkcyjnej rozproszonej pamięci podręcznej tokenów (na przykład: Redis, Microsoft SQL Server, Microsoft Azure Cosmos DB).

Note

W przypadku lokalnego programowania i testowania na jednym komputerze można używać pamięci podręcznych tokenów w pamięci zamiast rozproszonych pamięci podręcznych tokenów:

builder.Services.AddInMemoryTokenCaches();

W dalszej części okresu programowania i testowania zastosować dostawcę produkcyjnej rozproszonej pamięci podręcznej tokenów.

AddDistributedMemoryCache dodaje domyślną implementację IDistributedCache, która przechowuje w pamięci elementy pamięci podręcznej, używane przez Microsoft Identity Web do buforowania tokenów.

Rozproszona pamięć podręczna tokenów jest skonfigurowana przez usługę MsalDistributedTokenCacheAdapterOptions:

builder.Services.AddDistributedMemoryCache();

builder.Services.Configure<MsalDistributedTokenCacheAdapterOptions>(
    options => 
    {
      // The following lines that are commented out reflect
      // default values. We recommend overriding the default
      // value of Encrypt to encrypt tokens at rest.

      //options.DisableL1Cache = false;
      //options.L1CacheOptions.SizeLimit = 500 * 1024 * 1024;
      options.Encrypt = true;
      //options.SlidingExpiration = TimeSpan.FromHours(1);
    });

AddDistributedMemoryCache wymaga odwołania do Microsoft.Extensions.Caching.Memory pakietu NuGet.

Note

Aby uzyskać wskazówki dotyczące dodawania pakietów do aplikacji .NET, zobacz artykuły w Instalowanie i zarządzanie pakietami oraz w proces korzystania z pakietów (dokumentacja NuGet). Sprawdź prawidłowe wersje pakietów pod adresem NuGet.org.

Aby skonfigurować produkcyjny dostawcę cache'a rozproszonego, zapoznaj się z Rozproszonym buforowaniem w ASP.NET Core.

Warning

Zawsze zastępuj rozproszone pamięci podręczne tokenów w pamięci rzeczywistym dostawcą pamięci podręcznej tokenów, kiedy wdrażasz aplikację w środowisku produkcyjnym. Jeśli nie wdrożysz produkcyjnego dostawcy rozproszonej pamięci podręcznej tokenów, aplikacja może znacznie obniżyć wydajność.

Aby uzyskać więcej informacji, zobacz Serializacja pamięci podręcznej tokenów: rozproszone pamięci podręczne. Jednak pokazane przykłady kodu nie mają zastosowania do aplikacji ASP.NET Core, które konfigurują rozproszone pamięci podręczne za pośrednictwem metody AddDistributedMemoryCache, a nie AddDistributedTokenCache.

Użyj udostępnionego pierścienia kluczy ochrony danych w środowisku produkcyjnym, aby instancje aplikacji w serwerowni mogły odszyfrowywać tokeny, gdy MsalDistributedTokenCacheAdapterOptions.Encrypt jest ustawiona na truewartość.

Note

W przypadku wczesnego rozwoju i lokalnego testowania na jednej maszynie można ustawić Encrypt na false i skonfigurować wspólny kluczowy pierścień ochrony danych później:

options.Encrypt = false;

W dalszej części okresu programowania i testowania włącz szyfrowanie tokenów i zastosuj udostępniony pierścień kluczy ochrony danych.

W poniższym przykładzie pokazano, jak używać usług Azure Blob Storage i Azure Key Vault (PersistKeysToAzureBlobStorage/ProtectKeysWithAzureKeyVault) dla udostępnionego pierścienia kluczy. Konfiguracje usługi to scenariusze przypadków podstawowych w celach demonstracyjnych. Przed wdrożeniem aplikacji produkcyjnych zapoznaj się z usługami platformy Azure i zastosuj najlepsze rozwiązania przy użyciu dedykowanych zestawów dokumentacji usług platformy Azure połączonych na końcu tej sekcji.

Potwierdź obecność następujących pakietów w projekcie serwera programu Blazor Web App:

Note

Aby uzyskać wskazówki dotyczące dodawania pakietów do aplikacji .NET, zobacz artykuły w Instalowanie i zarządzanie pakietami oraz w proces korzystania z pakietów (dokumentacja NuGet). Sprawdź prawidłowe wersje pakietów pod adresem NuGet.org.

Note

Przed wykonaniem poniższych kroków upewnij się, że aplikacja jest zarejestrowana w usłudze Microsoft Entra.

Poniższy kod zwykle implementuje się równocześnie z implementacją rozproszonego dostawcy pamięci podręcznej tokenów w trybie produkcyjnym. Inne opcje, zarówno na platformie Azure, jak i poza platformą Azure, są dostępne do zarządzania kluczami ochrony danych w wielu wystąpieniach aplikacji, ale przykładowa aplikacja pokazuje, jak korzystać z usług platformy Azure.

Skonfiguruj usługę Azure Blob Storage, aby obsługiwać klucze ochrony danych. Postępuj zgodnie z instrukcjami w Dostawcy magazynu kluczy w ASP.NET Core.

Skonfiguruj usługę Azure Key Vault do szyfrowania kluczy ochrony danych w stanie spoczynku. Postępuj zgodnie ze wskazówkami w temacie Konfigurowanie podstawowej ochrony danych ASP.NET.

Użyj następującego Program kodu w pliku, w którym są zarejestrowane usługi:

TokenCredential? credential;

if (builder.Environment.IsProduction())
{
    credential = new ManagedIdentityCredential("{MANAGED IDENTITY CLIENT ID}");
}
else
{
    // Local development and testing only
    DefaultAzureCredentialOptions options = new()
    {
        // Specify the tenant ID to use the dev credentials when running the app locally
        // in Visual Studio.
        VisualStudioTenantId = "{TENANT ID}",
        SharedTokenCacheTenantId = "{TENANT ID}"
    };

    credential = new DefaultAzureCredential(options);
}

builder.Services.AddDataProtection()
    .SetApplicationName("BlazorWebAppEntra")
    .PersistKeysToAzureBlobStorage(new Uri("{BLOB URI}"), credential)
    .ProtectKeysWithAzureKeyVault(new Uri("{KEY IDENTIFIER}"), credential);

Możesz przekazać dowolną nazwę aplikacji do SetApplicationName. Upewnij się, że wszystkie wdrożenia aplikacji używają tej samej wartości.

{MANAGED IDENTITY CLIENT ID}: identyfikator klienta zarządzanego Identity platformy Azure (GUID).

{TENANT ID}: Identyfikator dzierżawcy.

{BLOB URI}: pełny identyfikator URI do pliku klucza. Identyfikator URI jest generowany przez usługę Azure Storage podczas tworzenia pliku klucza. Nie używaj SAS.

{KEY IDENTIFIER}: identyfikator klucza usługi Azure Key Vault używany do szyfrowania kluczy. Zasady dostępu umożliwiają aplikacji dostęp do magazynu kluczy z uprawnieniami Get, Unwrap Key i Wrap Key. Wersja klucza jest uzyskiwana z klucza w portalu Entra lub Azure po jego stworzeniu. Jeśli włączysz autorotację klucza w magazynie kluczy, upewnij się, że używasz identyfikatora klucza bez wersjonowania w konfiguracji magazynu kluczy aplikacji, gdzie na końcu identyfikatora nie znajduje się identyfikator GUID klucza (na przykład: https://contoso.vault.azure.net/keys/data-protection).

Note

W środowiskach nieprodukcyjnych w poprzednim przykładzie użyto DefaultAzureCredential metody upraszczania uwierzytelniania podczas opracowywania aplikacji wdrażanych na platformie Azure przez połączenie poświadczeń używanych w środowiskach hostingu platformy Azure z poświadczeniami używanymi w środowisku lokalnym. Aby uzyskać więcej informacji, zobacz Uwierzytelnianie aplikacji platformy .NET hostowanych na platformie Azure do zasobów platformy Azure przy użyciu tożsamości zarządzanej przypisanej przez system.

Alternatywnie możesz skonfigurować aplikację tak, aby dostarczała wartości z plików ustawień aplikacji przy użyciu dostawcy konfiguracji JSON. Dodaj następujące elementy do pliku ustawień aplikacji:

"DistributedTokenCache": {
  "DisableL1Cache": false,
  "L1CacheSizeLimit": 524288000,
  "Encrypt": true,
  "SlidingExpirationInHours": 1
},
"DataProtection": {
  "BlobUri": "{BLOB URI}",
  "KeyIdentifier": "{KEY IDENTIFIER}"
}

Przykładowa DataProtection sekcja:

"DataProtection": {
  "BlobUri": "https://contoso.blob.core.windows.net/data-protection/keys.xml",
  "KeyIdentifier": "https://contoso.vault.azure.net/keys/data-protection"
}

Note

Identyfikator klucza w poprzednim przykładzie jest bez wersji. Na końcu identyfikatora nie ma wersji klucza GUID. Jest to szczególnie ważne, jeśli zdecydujesz się skonfigurować automatyczną rotację klucza. Aby uzyskać więcej informacji, zobacz Konfigurowanie automatycznego obracania kluczy kryptograficznych w usłudze Azure Key Vault: zasady rotacji kluczy.

Wprowadź następujące zmiany w Program pliku:

builder.Services.Configure<MsalDistributedTokenCacheAdapterOptions>(
    options =>
    {
+       var config = builder.Configuration.GetSection("DistributedTokenCache");

-       options.DisableL1Cache = false;
+       options.DisableL1Cache = config.GetValue<bool>("DisableL1Cache");

-       options.L1CacheOptions.SizeLimit = 500 * 1024 * 1024;
+       options.L1CacheOptions.SizeLimit = config.GetValue<long>("L1CacheSizeLimit");

-       options.Encrypt = true;
+       options.Encrypt = config.GetValue<bool>("Encrypt");

-       options.SlidingExpiration = TimeSpan.FromHours(1);
+       options.SlidingExpiration = 
+           TimeSpan.FromHours(config.GetValue<int>("SlidingExpirationInHours"));
    });

- builder.Services.AddDataProtection()
-     .SetApplicationName("BlazorWebAppEntra")
-     .PersistKeysToAzureBlobStorage(new Uri("{BLOB URI}"), credential)
-     .ProtectKeysWithAzureKeyVault(new Uri("{KEY IDENTIFIER}"), credential);

Dodaj następujący kod, w którym usługi są skonfigurowane w Program pliku:

var config = builder.Configuration.GetSection("DataProtection");

builder.Services.AddDataProtection()
    .SetApplicationName("BlazorWebAppEntra")
    .PersistKeysToAzureBlobStorage(
        new Uri(config.GetValue<string>("BlobUri") ??
        throw new Exception("Missing Blob URI")),
        credential)
    .ProtectKeysWithAzureKeyVault(
        new Uri(config.GetValue<string>("KeyIdentifier") ?? 
        throw new Exception("Missing Key Identifier")), 
        credential);

Aby uzyskać więcej informacji na temat korzystania z udostępnianego pierścienia kluczy ochrony danych i dostawców pamięci kluczy, zobacz następujące zasoby:

Prefiks docelowy usługi przesyłania dalej YARP

Przekaźnik YARP projektu serwera Blazor Web App, w którym token dostępu użytkownika jest dołączany do wywołania interfejsu API MinimalApiJwt, określa docelowy prefiks https://weatherapi. Ta wartość odpowiada nazwie projektu przekazanej do AddProject w pliku Program projektu Aspire.AppHost.

Przesyłanie dalej w projekcie serwera Blazor Web App (BlazorWebAppEntra):

app.MapForwarder("/weather-forecast", "https://weatherapi", transformBuilder =>
{
    ...
}).RequireAuthorization();

Pasująca nazwa projektu Program w pliku Aspire projektu hosta aplikacji (Aspire.AppHost):

var weatherApi = builder.AddProject<Projects.MinimalApiJwt>("weatherapi");

Nie trzeba zmieniać prefiksu docelowego usługi przesyłania dalej YARP podczas wdrażania Blazor Web App w środowisku produkcyjnym. Pakiet Microsoft Identity Web Downstream API używa podstawowego identyfikatora URI przekazanego za pośrednictwem konfiguracji do nawiązania połączenia z internetowym interfejsem API z ServerWeatherForecaster, a nie z prefiksu docelowego narzędzia przesyłania dalej YARP. W środowisku produkcyjnym usługa przesyłania dalej YARP jedynie przekształca żądanie, dodając token dostępu użytkownika.

Przekieruj do strony głównej po wylogowaniu

Składnik LogInOrOut (Layout/LogInOrOut.razor) ustawia ukryte pole dla zwracanego adresu URL (ReturnUrl) na bieżący adres URL (currentURL). Gdy użytkownik wyloguje się z aplikacji, dostawca tożsamości zwraca użytkownika do strony, z której się wylogował. Jeśli użytkownik wyloguje się z bezpiecznej strony, zostanie zwrócony do tej samej bezpiecznej strony i odesłany przez proces uwierzytelniania. Ten przepływ uwierzytelniania jest rozsądny, gdy użytkownicy muszą regularnie zmieniać konta.

Alternatywnie użyj następującego składnika LogInOrOut, który nie dostarcza adresu URL zwrotnego podczas wylogowywania.

Layout/LogInOrOut.razor:

<div class="nav-item px-3">
    <AuthorizeView>
        <Authorized>
            <form action="authentication/logout" method="post">
                <AntiforgeryToken />
                <button type="submit" class="nav-link">
                    <span class="bi bi-arrow-bar-left-nav-menu" aria-hidden="true">
                    </span> Logout
                </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>

Zabezpieczenia danych pogodowych

Aby uzyskać więcej informacji na temat zabezpieczania danych pogodowych przez tę aplikację, zobacz Secure data in s with Interactive Auto rendering (Zabezpieczanie danych w programie Blazor Web Apps za pomocą renderowania interakcyjnego).

Troubleshoot

Logging

Aplikacja serwera jest standardową aplikacją ASP.NET Core. Zobacz wskazówki dotyczące logowania w ASP.NET Core, aby zmniejszyć poziom szczegółowości logów w aplikacji serwerowej.

Aby włączyć rejestrowanie debugowania lub śledzenia na potrzeby Blazor WebAssembly uwierzytelniania, zobacz sekcję Rejestrowanie uwierzytelniania po stronie klienta ASP.NET Core Blazor z selektorem wersji artykułu ustawionym na ASP.NET Core na platformie .NET 7 lub nowszym.

Typowe błędy

  • Debugger zatrzymuje się na wyjątku podczas wylogowywania z Microsoft Entra External ID.

    Następujący wyjątek zatrzymuje debuger programu Visual Studio podczas wylogowywania z Microsoft Entra External ID:

    Uncaught TypeError TypeError: Failed to execute 'postMessage' on 'Window': The provided value cannot be converted to a sequence.

    Niezgodność debugera programu Visual Studio w wyjątku języka JavaScript podczas wylogowywanie

    Wyjątek jest zgłaszany z kodu Entra JavaScript, więc nie jest to problem z ASP.NET Core. Wyjątek nie ma wpływu na funkcjonalność aplikacji w środowisku produkcyjnym, więc wyjątek można zignorować podczas lokalnego testowania programistycznego.

  • Błędna konfiguracja aplikacji lub Identity dostawcy (IP)

    Najczęstsze błędy są spowodowane nieprawidłową konfiguracją. Poniżej przedstawiono kilka przykładów:

    • W zależności od wymagań scenariusza, brakujący lub niepoprawny urząd, wystąpienie, identyfikator dzierżawcy, domena dzierżawcy, identyfikator klienta lub URI przekierowania uniemożliwia aplikacji uwierzytelnienie klientów.
    • Nieprawidłowe zakresy żądań uniemożliwiają klientom uzyskiwanie dostępu do punktów końcowych internetowego interfejsu API serwera.
    • Nieprawidłowe lub brakujące uprawnienia interfejsu API serwera uniemożliwiają klientom uzyskiwanie dostępu do punktów końcowych internetowego interfejsu API serwera.
    • Uruchamianie aplikacji na innym porcie niż ten skonfigurowany w przekierowaniu URI w rejestracji aplikacji powiązanej z adresem IP. Należy pamiętać, że port nie jest wymagany dla Microsoft Entra ID i aplikacji działającej pod localhost adresem testowym dewelopera, ale konfiguracja portu aplikacji i port, na którym działa aplikacja, muszą być zgodne z adresami, które nie są localhost.

    Omówienie konfiguracji w tym artykule przedstawia przykłady prawidłowej konfiguracji. Dokładnie sprawdź konfigurację wyszukując błędną konfigurację aplikacji i adresu IP.

    Jeśli konfiguracja jest poprawna:

    • Analizowanie dzienników aplikacji.

    • Sprawdź ruch sieciowy między aplikacją kliencka a adresem IP lub aplikacją serwera przy użyciu narzędzi deweloperskich przeglądarki. Często dokładny komunikat o błędzie lub komunikat zawierający wskazówki dotyczące przyczyn problemu jest zwracany do klienta przez adres IP lub aplikację serwera po wykonaniu żądania. Wskazówki dotyczące narzędzi programistycznych można znaleźć w następujących artykułach.

    Zespół dokumentacji odpowiada na opinie dotyczące dokumentów i usterek w artykułach (otwórz problem z sekcji Ta strona opinii), ale nie może zapewnić pomocy technicznej dotyczącej produktów. Dostępnych jest kilka publicznych forów pomocy technicznej, które ułatwiają rozwiązywanie problemów z aplikacją. Zalecamy:

    Poprzednie fora nie należą do firmy Microsoft ani nie są kontrolowane przez firmę Microsoft.

    W przypadku raportów o usterkach frameworka, które nie dotyczą zabezpieczeń, nie zawierają wrażliwych informacji i nie są poufne, otwórz zgłoszenie w jednostce produktu ASP.NET Core. Nie otwieraj problemu z jednostką produktu, dopóki nie zbadasz dokładnie przyczyny problemu i nie możesz go rozwiązać samodzielnie i z pomocą społeczności na publicznym forum pomocy technicznej. Jednostka produktu nie może rozwiązywać problemów z poszczególnymi aplikacjami, które są uszkodzone z powodu prostej błędnej konfiguracji lub przypadków użycia obejmujących usługi innych firm. Jeśli raport jest poufny lub poufny lub opisuje potencjalną lukę w zabezpieczeniach produktu, którą mogą wykorzystać cyberataki, zobacz Raportowanie problemów z zabezpieczeniami i usterek (dotnet/aspnetcorerepozytorium GitHub).

  • Nieautoryzowany klient ME-ID

    info: Autoryzacja Microsoft.AspNetCore.Authorization.DefaultAuthorizationService[2] nie powiodła się. Te wymagania nie zostały spełnione: DenyAnonymousAuthorizationRequirement: Wymaga uwierzytelnionego użytkownika.

    Błąd wywołania zwrotnego logowania z identyfikatora ME-ID:

    • Błąd: unauthorized_client
    • Opis: AADB2C90058: The provided application is not configured to allow public clients.

    Aby naprawić ten błąd:

    1. W witrynie Azure Portal uzyskaj dostęp do manifestu aplikacji.
    2. allowPublicClient Ustaw atrybut na null lub true.

Pliki cookie i dane witryn

Pliki cookie i dane witryn mogą być utrwalane w aktualizacjach aplikacji i zakłócać testowanie i rozwiązywanie problemów. Wyczyść następujące informacje podczas wprowadzania zmian w kodzie aplikacji, zmiany konta użytkownika w dostawcy lub zmiany konfiguracji aplikacji dostawcy:

  • Pliki cookie logowania użytkownika
  • Pliki cookie aplikacji
  • Buforowane i przechowywane dane lokacji

Jedną z metod zapobiegania temu, aby utrzymujące się pliki cookie i dane witryny nie zakłócały testowania i rozwiązywania problemów, jest:

  • Konfigurowanie przeglądarki
    • Używaj przeglądarki do testowania, którą można skonfigurować, aby za każdym razem, kiedy jest zamykana, usuwała wszystkie cookie i dane witryny.
    • Upewnij się, że przeglądarka jest zamknięta ręcznie lub przez środowisko IDE w celu zmiany konfiguracji aplikacji, użytkownika testowego lub dostawcy.
  • Użyj polecenia niestandardowego, aby otworzyć przeglądarkę w trybie InPrivate lub Incognito w programie Visual Studio:
    • Otwórz okno dialogowe Przeglądaj za pomocą z przycisku Uruchom programu Visual Studio.
    • Wybierz przycisk Dodaj .
    • Podaj ścieżkę do przeglądarki w polu Program . Następujące ścieżki wykonywalne to typowe lokalizacje instalacji systemu Windows 10. Jeśli przeglądarka jest zainstalowana w innej lokalizacji lub nie używasz systemu Windows 10, podaj ścieżkę do pliku wykonywalnego przeglądarki.
      • 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
    • W polu Argumenty podaj opcję wiersza polecenia używaną przez przeglądarkę do otwierania w trybie InPrivate lub Incognito. Niektóre przeglądarki wymagają adresu URL aplikacji.
      • Microsoft Edge: użyj -inprivate.
      • Google Chrome: użyj --incognito --new-window {URL}, gdzie {URL} to adres URL do otwarcia (na przykład https://localhost:5001).
      • Mozilla Firefox: użyj -private -url {URL}, gdzie {URL} to adres internetowy do otwarcia (na przykład https://localhost:5001).
    • Podaj nazwę w polu Przyjazna nazwa . Na przykład Firefox Auth Testing.
    • Wybierz przycisk OK .
    • Aby uniknąć konieczności wybierania profilu przeglądarki dla każdej iteracji testowania za pomocą aplikacji, ustaw profil jako domyślny przy użyciu przycisku Ustaw jako domyślny .
    • Upewnij się, że przeglądarka jest zamknięta przez środowisko IDE w celu zmiany konfiguracji aplikacji, użytkownika testowego lub dostawcy.

Uaktualnienia aplikacji

Działająca aplikacja może zakończyć się niepowodzeniem natychmiast po uaktualnieniu zestawu .NET SDK na komputerze deweloperskim lub zmianie wersji pakietów w aplikacji. W niektórych przypadkach niespójne pakiety mogą spowodować przerwanie aplikacji podczas przeprowadzania głównych uaktualnień. Większość z tych problemów można rozwiązać, wykonując następujące instrukcje:

  1. Wyczyść pamięć podręczną pakietów NuGet systemu lokalnego, wykonując polecenie dotnet nuget locals all --clear w wierszu poleceń.
  2. Usuń foldery bin i obj projektu.
  3. Przywracanie i odbudowanie projektu.
  4. Usuń wszystkie pliki w folderze wdrażania na serwerze przed ponownym wdrożeniem aplikacji.

Note

Korzystanie z wersji pakietów niezgodnych z platformą docelową aplikacji nie jest obsługiwane. Aby uzyskać informacje na temat pakietu, użyj galerii NuGet.

Uruchamianie rozwiązania z prawidłowego projektu

Blazor Web Apps:

  • W przypadku jednego z przykładów wzorca Backend-for-Frontend (BFF) uruchom rozwiązanie z Aspire/Aspire.AppHost projektu.
  • W przypadku jednego z przykładów wzorców innych niż BFF uruchom rozwiązanie z projektu serwera.

Blazor Server:

Uruchom rozwiązanie z projektu serwera.

Sprawdzanie użytkownika

Poniższy UserClaims składnik może być używany bezpośrednio w aplikacjach lub służyć jako podstawa dalszego dostosowywania.

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.Any())
{
    <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;
    }
}

Dodatkowe zasoby