Jak korzystać z tożsamości zarządzanej aplikacji usługi Service Fabric w celu uzyskania dostępu do usług platformy Azure

Aplikacje usługi Service Fabric mogą korzystać z tożsamości zarządzanych w celu uzyskania dostępu do innych zasobów platformy Azure, które obsługują uwierzytelnianie oparte na identyfikatorze Entra firmy Microsoft. Aplikacja może uzyskać token dostępu reprezentujący swoją tożsamość, która może być przypisana przez system lub przypisana przez użytkownika, i używać go jako tokenu elementu nośnego w celu uwierzytelnienia się w innej usłudze , znanej również jako chroniony serwer zasobów. Token reprezentuje tożsamość przypisaną do aplikacji usługi Service Fabric i zostanie wystawiona tylko dla zasobów platformy Azure (w tym aplikacji SF), które współużytkują tę tożsamość. Zapoznaj się z dokumentacją przeglądu tożsamości zarządzanej, aby uzyskać szczegółowy opis tożsamości zarządzanych, a także rozróżnienie między tożsamościami przypisanymi przez system i tożsamościami przypisanymi przez użytkownika. W tym artykule omówimy aplikację usługi Service Fabric z obsługą tożsamości zarządzanej jako aplikację kliencką.

Zobacz przykładową aplikację pomocniczą, która demonstruje używanie tożsamości zarządzanych aplikacji usługi Service Fabric przypisanych przez system i przypisanych przez użytkownika z usługami Reliable Services i kontenerami.

Ważne

Tożsamość zarządzana reprezentuje skojarzenie między zasobem platformy Azure i jednostką usługi w odpowiedniej dzierżawie firmy Microsoft Entra skojarzonej z subskrypcją zawierającą zasób. W związku z tym w kontekście usługi Service Fabric tożsamości zarządzane są obsługiwane tylko dla aplikacji wdrożonych jako zasoby platformy Azure.

Ważne

Przed użyciem tożsamości zarządzanej aplikacji usługi Service Fabric aplikacja kliencka musi mieć dostęp do chronionego zasobu. Zapoznaj się z listą usług platformy Azure, które obsługują uwierzytelnianie firmy Microsoft Entra, aby sprawdzić pomoc techniczną, a następnie zapoznaj się z dokumentacją odpowiedniej usługi, aby uzyskać szczegółowe instrukcje udzielania tożsamości dostępu do interesujących zasobów.

Korzystanie z tożsamości zarządzanej przy użyciu usługi Azure.Identity

Zestaw AZURE Identity SDK obsługuje teraz usługę Service Fabric. Użycie usługi Azure.Identity ułatwia pisanie kodu w celu korzystania z tożsamości zarządzanych aplikacji usługi Service Fabric, ponieważ obsługuje pobieranie tokenów, buforowanie tokenów i uwierzytelnianie serwera. Podczas uzyskiwania dostępu do większości zasobów platformy Azure pojęcie tokenu jest ukryte.

Obsługa usługi Service Fabric jest dostępna w następujących wersjach dla następujących języków:

Przykład inicjowania poświadczeń w języku C# i pobierania wpisu tajnego z usługi Azure Key Vault przy użyciu poświadczeń:

using Azure.Identity;
using Azure.Security.KeyVault.Secrets;

namespace MyMIService
{
    internal sealed class MyMIService : StatelessService
    {
        protected override async Task RunAsync(CancellationToken cancellationToken)
        {
            try
            {
                // Load the service fabric application managed identity assigned to the service
                ManagedIdentityCredential creds = new ManagedIdentityCredential();

                // Create a client to keyvault using that identity
                SecretClient client = new SecretClient(new Uri("https://mykv.vault.azure.net/"), creds);

                // Fetch a secret
                KeyVaultSecret secret = (await client.GetSecretAsync("mysecret", cancellationToken: cancellationToken)).Value;
            }
            catch (CredentialUnavailableException e)
            {
                // Handle errors with loading the Managed Identity
            }
            catch (RequestFailedException)
            {
                // Handle errors with fetching the secret
            }
            catch (Exception e)
            {
                // Handle generic errors
            }
        }
    }
}

Uzyskiwanie tokenu dostępu przy użyciu interfejsu API REST

W klastrach obsługujących tożsamość zarządzaną środowisko uruchomieniowe usługi Service Fabric uwidacznia punkt końcowy hosta lokalnego, którego aplikacje mogą używać do uzyskiwania tokenów dostępu. Punkt końcowy jest dostępny w każdym węźle klastra i jest dostępny dla wszystkich jednostek w tym węźle. Autoryzowane osoby wywołujące mogą uzyskać tokeny dostępu przez wywołanie tego punktu końcowego i przedstawienie kodu uwierzytelniania; kod jest generowany przez środowisko uruchomieniowe usługi Service Fabric dla każdej odrębnej aktywacji pakietu kodu usługi i jest powiązany z okresem istnienia procesu hostowania tego pakietu kodu usługi.

W szczególności środowisko usługi Service Fabric obsługującej tożsamość zarządzaną zostanie rozstawione z następującymi zmiennymi:

  • "IDENTITY_ENDPOINT": punkt końcowy hosta lokalnego odpowiadający tożsamości zarządzanej usługi
  • "IDENTITY_HEADER": unikatowy kod uwierzytelniania reprezentujący usługę w bieżącym węźle
  • "IDENTITY_SERVER_THUMBPRINT": odcisk palca serwera tożsamości zarządzanej usługi Service Fabric

Ważne

Kod aplikacji powinien rozważyć wartość zmiennej środowiskowej "IDENTITY_HEADER" jako poufne dane — nie należy ich rejestrować ani rozpowszechniać w inny sposób. Kod uwierzytelniania nie ma wartości poza węzłem lokalnym lub po zakończeniu procesu hostowania usługi, ale reprezentuje tożsamość usługi Service Fabric i dlatego powinny być traktowane z tymi samymi środkami ostrożności co sam token dostępu.

Aby uzyskać token, klient wykonuje następujące czynności:

  • tworzy identyfikator URI, łącząc punkt końcowy tożsamości zarządzanej (IDENTITY_ENDPOINT wartość) z wersją interfejsu API i zasobem (odbiorcy) wymaganym dla tokenu
  • Tworzy żądanie GET http dla określonego identyfikatora URI
  • dodaje odpowiednią logikę weryfikacji certyfikatu serwera
  • dodaje kod uwierzytelniania (IDENTITY_HEADER wartość) jako nagłówek do żądania
  • przesyła żądanie

Pomyślna odpowiedź będzie zawierać ładunek JSON reprezentujący wynikowy token dostępu, a także metadane opisujące go. Odpowiedź, która zakończyła się niepowodzeniem, będzie również zawierać wyjaśnienie błędu. Zobacz poniżej, aby uzyskać dodatkowe szczegóły dotyczące obsługi błędów.

Tokeny dostępu będą buforowane przez usługę Service Fabric na różnych poziomach (węzeł, klaster, usługa dostawcy zasobów), dlatego pomyślna odpowiedź nie musi oznaczać, że token został wystawiony bezpośrednio w odpowiedzi na żądanie aplikacji użytkownika. Tokeny będą buforowane przez krótszy niż ich okres istnienia, dlatego aplikacja ma gwarancję otrzymania prawidłowego tokenu. Zaleca się buforowanie kodu aplikacji w pamięci podręcznej wszystkich uzyskanych przez niego tokenów dostępu; klucz buforowania powinien zawierać (wyprowadzenie) odbiorców.

Przykładowe żądanie:

GET 'https://localhost:2377/metadata/identity/oauth2/token?api-version=2019-07-01-preview&resource=https://vault.azure.net/' HTTP/1.1 Secret: 912e4af7-77ba-4fa5-a737-56c8e3ace132

gdzie:

Element opis
GET Czasownik HTTP wskazujący, że chcesz pobrać dane z punktu końcowego. W takim przypadku token dostępu OAuth.
https://localhost:2377/metadata/identity/oauth2/token Punkt końcowy tożsamości zarządzanej dla aplikacji usługi Service Fabric udostępniany za pośrednictwem zmiennej środowiskowej IDENTITY_ENDPOINT.
api-version Parametr ciągu zapytania określający wersję interfejsu API usługi tokenu tożsamości zarządzanej; obecnie jedyną zaakceptowaną wartością jest 2019-07-01-preview, i może ulec zmianie.
resource Parametr ciągu zapytania wskazujący identyfikator URI identyfikatora aplikacji zasobu docelowego. Zostanie to odzwierciedlone jako aud oświadczenie (odbiorców) wystawionego tokenu. Ten przykład żąda tokenu w celu uzyskania dostępu do usługi Azure Key Vault, której identyfikator URI identyfikatora aplikacji to https://vault.azure.net/.
Secret Pole nagłówka żądania HTTP wymagane przez usługę Service Fabric Managed Identity Token Service dla usług Service Fabric do uwierzytelniania obiektu wywołującego. Ta wartość jest dostarczana przez środowisko uruchomieniowe SF za pośrednictwem zmiennej środowiskowej IDENTITY_HEADER.

Przykładowa odpowiedź:

HTTP/1.1 200 OK
Content-Type: application/json
{
    "token_type":  "Bearer",
    "access_token":  "eyJ0eXAiO...",
    "expires_on":  1565244611,
    "resource":  "https://vault.azure.net/"
}

gdzie:

Element opis
token_type Typ tokenu; w tym przypadku token dostępu "Bearer", co oznacza, że prezenter ('bearer') tego tokenu jest zamierzonym podmiotem tokenu.
access_token Żądany token dostępu. Podczas wywoływania zabezpieczonego interfejsu API REST token jest osadzony w Authorization polu nagłówka żądania jako token "elementu nośnego", co umożliwia interfejsowi API uwierzytelnianie obiektu wywołującego.
expires_on Sygnatura czasowa wygaśnięcia tokenu dostępu; reprezentowana jako liczba sekund od "1970-01-01T0:0:0Z UTC" i odpowiada oświadczenia tokenu exp . W takim przypadku token wygasa w dniu 2019-08-08T06:10:11+00:00 (w RFC 3339)
resource Zasób, dla którego wystawiono token dostępu, określony za pośrednictwem resource parametru ciągu zapytania żądania; odpowiada oświadczenia "aud" tokenu.

Uzyskiwanie tokenu dostępu przy użyciu języka C#

Powyższe staje się w języku C#:

namespace Azure.ServiceFabric.ManagedIdentity.Samples
{
    using System;
    using System.Net.Http;
    using System.Text;
    using System.Threading;
    using System.Threading.Tasks;
    using System.Web;
    using Newtonsoft.Json;

    /// <summary>
    /// Type representing the response of the SF Managed Identity endpoint for token acquisition requests.
    /// </summary>
    [JsonObject]
    public sealed class ManagedIdentityTokenResponse
    {
        [JsonProperty(Required = Required.Always, PropertyName = "token_type")]
        public string TokenType { get; set; }

        [JsonProperty(Required = Required.Always, PropertyName = "access_token")]
        public string AccessToken { get; set; }

        [JsonProperty(PropertyName = "expires_on")]
        public string ExpiresOn { get; set; }

        [JsonProperty(PropertyName = "resource")]
        public string Resource { get; set; }
    }

    /// <summary>
    /// Sample class demonstrating access token acquisition using Managed Identity.
    /// </summary>
    public sealed class AccessTokenAcquirer
    {
        /// <summary>
        /// Acquire an access token.
        /// </summary>
        /// <returns>Access token</returns>
        public static async Task<string> AcquireAccessTokenAsync()
        {
            var managedIdentityEndpoint = Environment.GetEnvironmentVariable("IDENTITY_ENDPOINT");
            var managedIdentityAuthenticationCode = Environment.GetEnvironmentVariable("IDENTITY_HEADER");
            var managedIdentityServerThumbprint = Environment.GetEnvironmentVariable("IDENTITY_SERVER_THUMBPRINT");
            // Latest api version, 2019-07-01-preview is still supported.
            var managedIdentityApiVersion = Environment.GetEnvironmentVariable("IDENTITY_API_VERSION");
            var managedIdentityAuthenticationHeader = "secret";
            var resource = "https://management.azure.com/";

            var requestUri = $"{managedIdentityEndpoint}?api-version={managedIdentityApiVersion}&resource={HttpUtility.UrlEncode(resource)}";

            var requestMessage = new HttpRequestMessage(HttpMethod.Get, requestUri);
            requestMessage.Headers.Add(managedIdentityAuthenticationHeader, managedIdentityAuthenticationCode);
            
            var handler = new HttpClientHandler();
            handler.ServerCertificateCustomValidationCallback = (httpRequestMessage, cert, certChain, policyErrors) =>
            {
                // Do any additional validation here
                if (policyErrors == SslPolicyErrors.None)
                {
                    return true;
                }
                return 0 == string.Compare(cert.GetCertHashString(), managedIdentityServerThumbprint, StringComparison.OrdinalIgnoreCase);
            };

            try
            {
                var response = await new HttpClient(handler).SendAsync(requestMessage)
                    .ConfigureAwait(false);

                response.EnsureSuccessStatusCode();

                var tokenResponseString = await response.Content.ReadAsStringAsync()
                    .ConfigureAwait(false);

                var tokenResponseObject = JsonConvert.DeserializeObject<ManagedIdentityTokenResponse>(tokenResponseString);

                return tokenResponseObject.AccessToken;
            }
            catch (Exception ex)
            {
                string errorText = String.Format("{0} \n\n{1}", ex.Message, ex.InnerException != null ? ex.InnerException.Message : "Acquire token failed");

                Console.WriteLine(errorText);
            }

            return String.Empty;
        }
    } // class AccessTokenAcquirer
} // namespace Azure.ServiceFabric.ManagedIdentity.Samples

Uzyskiwanie dostępu do usługi Key Vault z aplikacji usługi Service Fabric przy użyciu tożsamości zarządzanej

Ten przykład opiera się na powyższych elementach, aby zademonstrować dostęp do wpisu tajnego przechowywanego w usłudze Key Vault przy użyciu tożsamości zarządzanej.

        /// <summary>
        /// Probe the specified secret, displaying metadata on success.  
        /// </summary>
        /// <param name="vault">vault name</param>
        /// <param name="secret">secret name</param>
        /// <param name="version">secret version id</param>
        /// <returns></returns>
        public async Task<string> ProbeSecretAsync(string vault, string secret, string version)
        {
            // initialize a KeyVault client with a managed identity-based authentication callback
            var kvClient = new Microsoft.Azure.KeyVault.KeyVaultClient(new Microsoft.Azure.KeyVault.KeyVaultClient.AuthenticationCallback((a, r, s) => { return AuthenticationCallbackAsync(a, r, s); }));

            Log(LogLevel.Info, $"\nRunning with configuration: \n\tobserved vault: {config.VaultName}\n\tobserved secret: {config.SecretName}\n\tMI endpoint: {config.ManagedIdentityEndpoint}\n\tMI auth code: {config.ManagedIdentityAuthenticationCode}\n\tMI auth header: {config.ManagedIdentityAuthenticationHeader}");
            string response = String.Empty;

            Log(LogLevel.Info, "\n== {DateTime.UtcNow.ToString()}: Probing secret...");
            try
            {
                var secretResponse = await kvClient.GetSecretWithHttpMessagesAsync(vault, secret, version)
                    .ConfigureAwait(false);

                if (secretResponse.Response.IsSuccessStatusCode)
                {
                    // use the secret: secretValue.Body.Value;
                    response = String.Format($"Successfully probed secret '{secret}' in vault '{vault}': {PrintSecretBundleMetadata(secretResponse.Body)}");
                }
                else
                {
                    response = String.Format($"Non-critical error encountered retrieving secret '{secret}' in vault '{vault}': {secretResponse.Response.ReasonPhrase} ({secretResponse.Response.StatusCode})");
                }
            }
            catch (Microsoft.Rest.ValidationException ve)
            {
                response = String.Format($"encountered REST validation exception 0x{ve.HResult.ToString("X")} trying to access '{secret}' in vault '{vault}' from {ve.Source}: {ve.Message}");
            }
            catch (KeyVaultErrorException kvee)
            {
                response = String.Format($"encountered KeyVault exception 0x{kvee.HResult.ToString("X")} trying to access '{secret}' in vault '{vault}': {kvee.Response.ReasonPhrase} ({kvee.Response.StatusCode})");
            }
            catch (Exception ex)
            {
                // handle generic errors here
                response = String.Format($"encountered exception 0x{ex.HResult.ToString("X")} trying to access '{secret}' in vault '{vault}': {ex.Message}");
            }

            Log(LogLevel.Info, response);

            return response;
        }

        /// <summary>
        /// KV authentication callback, using the application's managed identity.
        /// </summary>
        /// <param name="authority">The expected issuer of the access token, from the KV authorization challenge.</param>
        /// <param name="resource">The expected audience of the access token, from the KV authorization challenge.</param>
        /// <param name="scope">The expected scope of the access token; not currently used.</param>
        /// <returns>Access token</returns>
        public async Task<string> AuthenticationCallbackAsync(string authority, string resource, string scope)
        {
            Log(LogLevel.Verbose, $"authentication callback invoked with: auth: {authority}, resource: {resource}, scope: {scope}");
            var encodedResource = HttpUtility.UrlEncode(resource);

            // This sample does not illustrate the caching of the access token, which the user application is expected to do.
            // For a given service, the caching key should be the (encoded) resource uri. The token should be cached for a period
            // of time at most equal to its remaining validity. The 'expires_on' field of the token response object represents
            // the number of seconds from Unix time when the token will expire. You may cache the token if it will be valid for at
            // least another short interval (1-10s). If its expiration will occur shortly, don't cache but still return it to the 
            // caller. The MI endpoint will not return an expired token.
            // Sample caching code:
            //
            // ManagedIdentityTokenResponse tokenResponse;
            // if (responseCache.TryGetCachedItem(encodedResource, out tokenResponse))
            // {
            //     Log(LogLevel.Verbose, $"cache hit for key '{encodedResource}'");
            //
            //     return tokenResponse.AccessToken;
            // }
            //
            // Log(LogLevel.Verbose, $"cache miss for key '{encodedResource}'");
            //
            // where the response cache is left as an exercise for the reader. MemoryCache is a good option, albeit not yet available on .net core.

            var requestUri = $"{config.ManagedIdentityEndpoint}?api-version={config.ManagedIdentityApiVersion}&resource={encodedResource}";
            Log(LogLevel.Verbose, $"request uri: {requestUri}");

            var requestMessage = new HttpRequestMessage(HttpMethod.Get, requestUri);
            requestMessage.Headers.Add(config.ManagedIdentityAuthenticationHeader, config.ManagedIdentityAuthenticationCode);
            Log(LogLevel.Verbose, $"added header '{config.ManagedIdentityAuthenticationHeader}': '{config.ManagedIdentityAuthenticationCode}'");

            var response = await httpClient.SendAsync(requestMessage)
                .ConfigureAwait(false);
            Log(LogLevel.Verbose, $"response status: success: {response.IsSuccessStatusCode}, status: {response.StatusCode}");

            response.EnsureSuccessStatusCode();

            var tokenResponseString = await response.Content.ReadAsStringAsync()
                .ConfigureAwait(false);

            var tokenResponse = JsonConvert.DeserializeObject<ManagedIdentityTokenResponse>(tokenResponseString);
            Log(LogLevel.Verbose, "deserialized token response; returning access code..");

            // Sample caching code (continuation):
            // var expiration = DateTimeOffset.FromUnixTimeSeconds(Int32.Parse(tokenResponse.ExpiresOn));
            // if (expiration > DateTimeOffset.UtcNow.AddSeconds(5.0))
            //    responseCache.AddOrUpdate(encodedResource, tokenResponse, expiration);

            return tokenResponse.AccessToken;
        }

        private string PrintSecretBundleMetadata(SecretBundle bundle)
        {
            StringBuilder strBuilder = new StringBuilder();

            strBuilder.AppendFormat($"\n\tid: {bundle.Id}\n");
            strBuilder.AppendFormat($"\tcontent type: {bundle.ContentType}\n");
            strBuilder.AppendFormat($"\tmanaged: {bundle.Managed}\n");
            strBuilder.AppendFormat($"\tattributes:\n");
            strBuilder.AppendFormat($"\t\tenabled: {bundle.Attributes.Enabled}\n");
            strBuilder.AppendFormat($"\t\tnbf: {bundle.Attributes.NotBefore}\n");
            strBuilder.AppendFormat($"\t\texp: {bundle.Attributes.Expires}\n");
            strBuilder.AppendFormat($"\t\tcreated: {bundle.Attributes.Created}\n");
            strBuilder.AppendFormat($"\t\tupdated: {bundle.Attributes.Updated}\n");
            strBuilder.AppendFormat($"\t\trecoveryLevel: {bundle.Attributes.RecoveryLevel}\n");

            return strBuilder.ToString();
        }

        private enum LogLevel
        {
            Info,
            Verbose
        };

        private void Log(LogLevel level, string message)
        {
            if (level != LogLevel.Verbose
                || config.DoVerboseLogging)
            {
                Console.WriteLine(message);
            }
        }

Obsługa błędów

Pole "kod stanu" nagłówka odpowiedzi HTTP wskazuje stan powodzenia żądania; Stan "200 OK" wskazuje powodzenie, a odpowiedź będzie zawierać token dostępu zgodnie z powyższym opisem. Poniżej przedstawiono krótkie wyliczenie możliwych odpowiedzi na błędy.

Kod stanu Przyczyna błędu Jak obsługiwać
404 Nie znaleziono. Nieznany kod uwierzytelniania lub aplikacja nie została przypisana tożsamości zarządzanej. Sprostowanie konfiguracji aplikacji lub kodu pozyskiwania tokenu.
429 Zbyt wiele żądań. Osiągnięto limit ograniczania, narzucony przez identyfikator entra firmy Microsoft lub SF. Ponów próbę przy użyciu wycofywania wykładniczego. Zobacz wskazówki poniżej.
Błąd 4xx w żądaniu. Co najmniej jeden parametr żądania był niepoprawny. Nie ponawiaj próby. Sprawdź szczegóły błędu, aby uzyskać więcej informacji. Błędy 4xx to błędy czasu projektowania.
Błąd 5xx z usługi. Podsystem tożsamości zarządzanej lub identyfikator Entra firmy Microsoft zwrócił błąd przejściowy. Po krótkiej chwili można bezpiecznie ponowić próbę. Po ponowieniu próby może wystąpić warunek ograniczania przepustowości (429).

Jeśli wystąpi błąd, odpowiednia treść odpowiedzi HTTP zawiera obiekt JSON ze szczegółami błędu:

Element opis
code Kod błędu.
correlationId Identyfikator korelacji, który może służyć do debugowania.
wiadomość Pełny opis błędu. Opisy błędów mogą ulec zmianie w dowolnym momencie. Nie należy zależeć od samego komunikatu o błędzie.

Przykładowy błąd:

{"error":{"correlationId":"7f30f4d3-0f3a-41e0-a417-527f21b3848f","code":"SecretHeaderNotFound","message":"Secret is not found in the request headers."}}

Poniżej znajduje się lista typowych błędów usługi Service Fabric specyficznych dla tożsamości zarządzanych:

Kod Wiadomość opis
SecretHeaderNotFound Wpis tajny nie znajduje się w nagłówkach żądań. Kod uwierzytelniania nie został dostarczony z żądaniem.
ManagedIdentityNotFound Nie można odnaleźć tożsamości zarządzanej dla określonego hosta aplikacji. Aplikacja nie ma tożsamości lub kod uwierzytelniania jest nieznany.
ArgumentNullOrEmpty Parametr "resource" nie powinien mieć wartości null ani ciągu pustego. Zasób (odbiorcy) nie został podany w żądaniu.
InvalidApiVersion Wersja interfejsu API "" nie jest obsługiwana. Obsługiwana wersja to "2019-07-01-preview". Brak lub nieobsługiwana wersja interfejsu API określona w identyfikatorze URI żądania.
InternalServerError Wystąpił błąd. Wystąpił błąd w podsystemie tożsamości zarządzanej, prawdopodobnie poza stosem usługi Service Fabric. Najprawdopodobniej przyczyną jest nieprawidłowa wartość określona dla zasobu (sprawdź końcowy ciąg "/"?)

Wskazówki dotyczące ponawiania prób

Zazwyczaj jedynym kodem błędu, który można ponowić, jest 429 (zbyt wiele żądań); wewnętrzne błędy serwera/kody błędów 5xx mogą być ponawiane, chociaż przyczyna może być trwała.

Ograniczenia przepustowości dotyczą liczby wywołań do podsystemu tożsamości zarządzanej — w szczególności zależności "nadrzędnych" (usługi platformy Azure tożsamości zarządzanej lub usługi bezpiecznego tokenu). Usługa Service Fabric buforuje tokeny na różnych poziomach w potoku, ale biorąc pod uwagę rozproszony charakter zaangażowanych składników, obiekt wywołujący może napotkać niespójne odpowiedzi ograniczania przepustowości (tj. zostać ograniczone w jednym węźle/wystąpieniu aplikacji, ale nie w innym węźle podczas żądania tokenu dla tej samej tożsamości). Jeśli warunek ograniczania jest ustawiony, kolejne żądania z tej samej aplikacji mogą zakończyć się niepowodzeniem z kodem stanu HTTP 429 (Zbyt wiele żądań), dopóki warunek nie zostanie wyczyszczone.

Zaleca się, aby żądania nie powiodły się z powodu ograniczania przepustowości są ponawiane z wycofywaniem wykładniczym w następujący sposób:

Indeks wywołań Akcja odbierania 429
1 Poczekaj 1 sekundę i spróbuj ponownie
2 Poczekaj 2 sekundy i spróbuj ponownie
3 Poczekaj 4 sekundy i spróbuj ponownie
4 Poczekaj 8 sekund i spróbuj ponownie
4 Poczekaj 8 sekund i spróbuj ponownie
5 Poczekaj 16 sekund i ponów próbę

Identyfikatory zasobów dla usług platformy Azure

Zobacz Usługi platformy Azure, które obsługują uwierzytelnianie Firmy Microsoft Entra, aby uzyskać listę zasobów obsługujących identyfikator Firmy Microsoft Entra i odpowiednie identyfikatory zasobów.

Następne kroki