Aufrufen nachgeschalteter APIs aus Web-APIs

In diesem Artikel wird gezeigt, wie Sie mithilfe von Microsoft.Identity.Web downstream-APIs aus ASP.NET Core- und OWIN-Web-APIs aufrufen. Der Artikel konzentriert sich auf den On-Behalf-Of(OBO)-Fluss, in dem Ihre API ein Token von einem Client empfängt und es für ein neues Token austauscht, um eine andere API aufzurufen.

Verständnis des On-Behalf-Of-Ablaufs

Mit dem On-Behalf-Of-Fluss (OBO) kann Ihre Web-API im Namen des Benutzers, der Ihre API aufgerufen hat, nachgelagerte APIs aufrufen. Dieser Fluss verwaltet die Identität und Berechtigungen des Benutzers in der gesamten Anrufkette.

Überprüfen des OBO-Flussdiagramms

Das folgende Diagramm zeigt, wie der OBO-Fluss zwischen Ihrer API, Microsoft Entra ID und der downstream-API funktioniert.

sequenceDiagram
    participant Client as Client App
    participant YourAPI as Your Web API
    participant AzureAD as Microsoft Entra ID
    participant DownstreamAPI as Downstream API

    Client->>YourAPI: 1. Call with access token
    Note over YourAPI: Validate token
    YourAPI->>AzureAD: 2. OBO request with user token
    AzureAD->>AzureAD: 3. Validate & check consent
    AzureAD->>YourAPI: 4. New access token for downstream API
    Note over YourAPI: Cache token for user
    YourAPI->>DownstreamAPI: 5. Call with new token
    DownstreamAPI->>YourAPI: 6. Return data
    YourAPI->>Client: 7. Return processed data

Überprüfen der Voraussetzungen

Bevor Sie beginnen, stellen Sie sicher, dass Folgendes vorhanden ist:

  • Web-API mit JWT Bearer-Authentifizierung konfiguriert
  • App-Registrierung mit API-Berechtigungen für nachgeschaltete APIs
  • Client-App muss über Berechtigungen zum Aufrufen Der API verfügen
  • Der Benutzer muss sowohl Ihrer API als auch der downstream-API zugestimmt haben.

Implementieren in ASP.NET Core

Die folgenden Schritte zeigen, wie Sie Ihre ASP.NET Core Web-API so konfigurieren, dass nachgeschaltete APIs mithilfe des OBO-Flusses aufgerufen werden.

1. Konfigurieren der Authentifizierung

Einrichten der JWT Bearer-Authentifizierung mit expliziten Authentifizierungsschemas:

using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Identity.Web;

var builder = WebApplication.CreateBuilder(args);

// Add authentication with explicit scheme
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd"))
    .EnableTokenAcquisitionToCallDownstreamApi()
    .AddInMemoryTokenCaches();

builder.Services.AddAuthorization();
builder.Services.AddControllers();

var app = builder.Build();

app.UseAuthentication();
app.UseAuthorization();

app.MapControllers();
app.Run();

2. Konfigurieren von appsettings.json

Fügen Sie Ihre Microsoft Entra App-Registrierungsdetails und die nachgeschaltete API-Konfiguration zu appsettings.json hinzu.

{
  "AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "TenantId": "your-tenant-id",
    "ClientId": "your-api-client-id",
    "ClientCredentials": [
      {
        "SourceType": "ClientSecret",
        "ClientSecret": "your-client-secret"
      }
    ],
    "Audience": "api://your-api-client-id"
  },
  "DownstreamApis": {
    "GraphAPI": {
      "BaseUrl": "https://graph.microsoft.com/v1.0",
      "Scopes": ["https://graph.microsoft.com/.default"]
    },
    "PartnerAPI": {
      "BaseUrl": "https://partnerapi.example.com",
      "Scopes": ["api://partner-api-id/read"]
    }
  }
}

3. Hinzufügen der Nachgelagerten API-Unterstützung

Registrieren Sie die nachgeschalteten APIs aus Ihrem Konfigurationsabschnitt.

using Microsoft.Identity.Web;

builder.Services.AddDownstreamApis(
    builder.Configuration.GetSection("DownstreamApis"));

4. Aufrufen der downstream-API aus Ihrer API

Integrieren Sie IDownstreamApi in Ihren Controller und verwenden Sie ihn, um nachgeschaltete APIs im Namen des Benutzers aufzurufen.

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Identity.Web;
using Microsoft.Identity.Abstractions;

[Authorize]
[ApiController]
[Route("api/[controller]")]
public class DataController : ControllerBase
{
    private readonly IDownstreamApi _downstreamApi;
    private readonly ILogger<DataController> _logger;

    public DataController(
        IDownstreamApi downstreamApi,
        ILogger<DataController> logger)
    {
        _downstreamApi = downstreamApi;
        _logger = logger;
    }

    [HttpGet("userdata")]
    public async Task<ActionResult<UserData>> GetUserData()
    {
        try
        {
            // Call downstream API using OBO flow
            // Token from incoming request is automatically used
            var userData = await _downstreamApi.GetForUserAsync<UserData>(
                "PartnerAPI",
                "api/users/me");

            return Ok(userData);
        }
        catch (MicrosoftIdentityWebChallengeUserException ex)
        {
            // User needs to consent to downstream API permissions
            _logger.LogWarning(ex, "User consent required for downstream API");
            return Unauthorized(new { error = "consent_required", scopes = ex.Scopes });
        }
        catch (HttpRequestException ex)
        {
            _logger.LogError(ex, "Downstream API call failed");
            return StatusCode(500, "Failed to retrieve data from downstream service");
        }
    }

    [HttpPost("process")]
    public async Task<ActionResult<ProcessResult>> ProcessData([FromBody] DataRequest request)
    {
        // Call downstream API with POST
        var result = await _downstreamApi.PostForUserAsync<DataRequest, ProcessResult>(
            "PartnerAPI",
            "api/process",
            request);

        return Ok(result);
    }
}

Tokenzwischenspeicherung konfigurieren

Wählen Sie eine Tokencachestrategie basierend auf Ihrer Bereitstellungsumgebung aus.

Verwenden Sie den In-Memory-Cache für die Entwicklung

Der folgende Code fügt einen Cache für In-Memory-Token hinzu, der nur für die Entwicklung geeignet ist.

builder.Services.AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd"))
    .EnableTokenAcquisitionToCallDownstreamApi()
    .AddInMemoryTokenCaches();

Warnung: Verwenden des verteilten Caches für die Produktion.

Verwenden des verteilten Caches für die Produktion

Verwenden Sie für Produktions-APIs mit mehreren Instanzen die verteilte Zwischenspeicherung:

using Microsoft.Extensions.Caching.StackExchangeRedis;

builder.Services.AddStackExchangeRedisCache(options =>
{
    options.Configuration = builder.Configuration.GetConnectionString("Redis");
    options.InstanceName = "MyWebApi";
});

builder.Services.AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd"))
    .EnableTokenAcquisitionToCallDownstreamApi()
    .AddDistributedTokenCaches();

Konfigurieren anderer verteilter Cacheanbieter

Sie können auch SQL Server, Cosmos DB oder PostgreSQL als Ihren verteilten Cacheanbieter verwenden.

// SQL Server
builder.Services.AddDistributedSqlServerCache(options =>
{
    options.ConnectionString = builder.Configuration.GetConnectionString("TokenCacheDb");
    options.SchemaName = "dbo";
    options.TableName = "TokenCache";
});

// Cosmos DB
builder.Services.AddCosmosDbTokenCaches(options =>
{
    options.DatabaseId = "TokenCache";
    options.ContainerId = "Tokens";
});

// PostgreSQL (requires Microsoft.Extensions.Caching.Postgres)
builder.Services.AddDistributedPostgresCache(options =>
{
    options.ConnectionString = builder.Configuration.GetConnectionString("PostgresCache");
    options.SchemaName = builder.Configuration["PostgresCache:SchemaName"];
    options.TableName = builder.Configuration["PostgresCache:TableName"];
    options.CreateIfNotExists = builder.Configuration.GetValue<bool>("PostgresCache:CreateIfNotExists");
});

Verwaltung lang andauernder Prozesse mit OBO

Für lange laufende Hintergrundprozesse benötigen Sie eine spezielle Behandlung, da das Token des Benutzers möglicherweise abläuft.

Verständnis der Herausforderung der Tokenablaufzeit

Das folgende Diagramm veranschaulicht, wie sich das Ablaufen von Token auf lang andauernde Prozesse auswirken kann.

graph TD
    A[Client calls API] --> B[API receives user token]
    B --> C[API starts long process]
    C --> D{Token expires?}
    D -->|Yes| E[ OBO fails]
    D -->|No| F[ OBO succeeds]

    style E fill:#f8d7da
    style F fill:#d4edda

Wählen Sie Sitzungsschlüsselstrategien

Langandauernde OBO-Prozesse verwenden einen Sitzungsschlüssel, um einem bestimmten Hintergrundworkflow ein zwischengespeichertes OBO-Token zuzuordnen. Es gibt zwei Optionen:

Vorgehensweise Wann verwenden?
Expliziter Schlüssel – Sie geben Ihren eigenen Schlüssel an (z. B. a Guid) Sie verfügen bereits über einen natürlichen Bezeichner für die Arbeitsaufgabe (Prozess-ID, Auftrags-ID usw.)
AllocateForMe – die Tokenebene generiert automatisch einen Schlüssel. Sie verfügen nicht über einen natürlichen Bezeichner, oder Sie möchten, dass die Identitätsplattform die Schlüssel-Eindeutigkeit verwaltet. Das SDK wird hash(client_token) intern verwenden.

Implementieren langer Prozesse mit einem expliziten Schlüssel

Das folgende Beispiel zeigt, wie Sie einen expliziten Schlüssel verwenden, z. B. eine Prozess-ID, für lange ausgeführte Hintergrundworkflows.

[Authorize]
[ApiController]
[Route("api/[controller]")]
public class ProcessingController : ControllerBase
{
    private readonly IDownstreamApi _downstreamApi;
    private readonly IBackgroundTaskQueue _taskQueue;

    public ProcessingController(
        IDownstreamApi downstreamApi,
        IBackgroundTaskQueue taskQueue)
    {
        _downstreamApi = downstreamApi;
        _taskQueue = taskQueue;
    }

    [HttpPost("start")]
    public async Task<ActionResult<ProcessStatus>> StartLongProcess([FromBody] ProcessRequest request)
    {
        var processId = Guid.NewGuid();

        // Queue the long-running task
        _taskQueue.QueueBackgroundWorkItem(async (cancellationToken) =>
        {
            await ProcessDataAsync(processId, request, cancellationToken);
        });

        return Accepted(new ProcessStatus
        {
            ProcessId = processId,
            Status = "Started"
        });
    }

    private async Task ProcessDataAsync(
        Guid processId,
        ProcessRequest request,
        CancellationToken cancellationToken)
    {
        try
        {
            // The cached refresh token allows token acquisition even if original token expired
            var data = await _downstreamApi.GetForUserAsync<ProcessData>(
                "PartnerAPI",
                options => {
                   options.RelativePath = "api/process/data";
                   options.AcquireTokenOptions.LongRunningWebApiSessionKey = processId.ToString()
                },
                cancellationToken: cancellationToken);

            // Process data...
            await Task.Delay(TimeSpan.FromMinutes(5), cancellationToken);

            // Call API again (token may need refresh)
            await _downstreamApi.PostForUserAsync<ProcessData, ProcessResult>(
                "PartnerAPI",
                options => {
                   options.RelativePath = "api/process/complete";
                   options.AcquireTokenOptions.LongRunningWebApiSessionKey = processId.ToString()
                },
                data,
                cancellationToken: cancellationToken);
        }
        catch (Exception ex)
        {
            // Log error and update process status
        }
    }
}

Implementieren von lang andauernden Prozessen mit AllocateForMe

Anstatt Ihren eigenen Schlüssel zu verwalten, legen Sie diesen auf den speziellen Sentinelwert LongRunningWebApiSessionKey (die ZeichenfolgeAcquireTokenOptions.LongRunningWebApiSessionKeyAuto) fest"AllocateForMe". Beim ersten Aufruf generiert die Tokenerfassungsebene automatisch einen eindeutigen Sitzungsschlüssel und schreibt ihn zurück in dieselbe AcquireTokenOptions Instanz. Anschließend lesen Sie den generierten Schlüssel und übergeben ihn an alle nachfolgenden Aufrufe.

[Authorize]
[ApiController]
[Route("api/[controller]")]
public class AutoKeyProcessingController : ControllerBase
{
    private readonly IDownstreamApi _downstreamApi;
    private readonly IBackgroundTaskQueue _taskQueue;

    public AutoKeyProcessingController(
        IDownstreamApi downstreamApi,
        IBackgroundTaskQueue taskQueue)
    {
        _downstreamApi = downstreamApi;
        _taskQueue = taskQueue;
    }

    [HttpPost("start")]
    public async Task<ActionResult<ProcessStatus>> StartLongProcess([FromBody] ProcessRequest request)
    {
        // First call: let the platform allocate a session key
        var options = new DownstreamApiOptions
        {
            RelativePath = "api/process/data",
            AcquireTokenOptions = new AcquireTokenOptions
            {
                // Sentinel value — the platform will replace this with a generated key
                LongRunningWebApiSessionKey = AcquireTokenOptions.LongRunningWebApiSessionKeyAuto  // "AllocateForMe"
            }
        };

        var data = await _downstreamApi.GetForUserAsync<ProcessData>(
            "PartnerAPI",
            optionsOverride => {
                optionsOverride.RelativePath = options.RelativePath;
                optionsOverride.AcquireTokenOptions.LongRunningWebApiSessionKey =
                    options.AcquireTokenOptions.LongRunningWebApiSessionKey;
            });

        // After the call, the platform has replaced the sentinel with the generated key.
        string generatedSessionKey = options.AcquireTokenOptions.LongRunningWebApiSessionKey;
        // generatedSessionKey is now a unique string such as "a1b2c3d4..." — no longer "AllocateForMe".

        // Queue background work using the generated key
        _taskQueue.QueueBackgroundWorkItem(async (cancellationToken) =>
        {
            await ContinueProcessingAsync(generatedSessionKey, data, cancellationToken);
        });

        return Accepted(new ProcessStatus
        {
            SessionKey = generatedSessionKey,
            Status = "Started"
        });
    }

    private async Task ContinueProcessingAsync(
        string sessionKey,
        ProcessData data,
        CancellationToken cancellationToken)
    {
        // Process data...
        await Task.Delay(TimeSpan.FromMinutes(5), cancellationToken);

        // Subsequent calls: reuse the generated session key
        await _downstreamApi.PostForUserAsync<ProcessData, ProcessResult>(
            "PartnerAPI",
            options => {
                options.RelativePath = "api/process/complete";
                options.AcquireTokenOptions.LongRunningWebApiSessionKey = sessionKey;
            },
            data,
            cancellationToken: cancellationToken);
    }
}

Wichtige Überlegungen überprüfen

Beachten Sie beim Implementieren langer OBO-Prozesse die folgenden Punkte.

  1. Sitzungsschlüssellebensdauer: Speichern Sie den generierten Sitzungsschlüssel zusammen mit Ihrer Arbeitsaufgabe (Datenbank, Warteschlangennachricht usw.), damit Hintergrundmitarbeiter ihn abrufen können.
  2. Tokencache: Verwenden sie verteilten Cache für Hintergrundprozesse.
  3. Benutzerkontext: Der Hintergrundarbeiter kann auf HttpContext.User zugreifen.
  4. Fehlerbehandlung: Das Token läuft möglicherweise noch ab, wenn der Benutzer die Zustimmung widerruft.

Behandeln von Fehlern in APIs

Web-APIs erfordern spezifische Fehlerbehandlungsmuster, da sie Benutzer nicht zu interaktiven Zustimmungsflüssen umleiten können.

Behandlung der MicrosoftIdentityWebChallengeUserException

In Web-APIs können Sie Benutzer nicht zur Zustimmung umleiten. Geben Sie stattdessen eine ordnungsgemäße Fehlerantwort zurück:

[HttpGet("data")]
public async Task<ActionResult> GetData()
{
    try
    {
        var data = await _downstreamApi.GetForUserAsync<Data>("PartnerAPI", "api/data");
        return Ok(data);
    }
    catch (MicrosoftIdentityWebChallengeUserException ex)
    {
        // Return 401 with consent information
        return Unauthorized(new
        {
            error = "consent_required",
            error_description = "Additional user consent required",
            scopes = ex.Scopes,
            claims = ex.Claims
        });
    }
}

Die Client-App sollte die 401-Antwort behandeln und die Zustimmung auslösen:

// Client app code
var response = await httpClient.GetAsync("https://yourapi.example.com/api/data");

if (response.StatusCode == HttpStatusCode.Unauthorized)
{
    var error = await response.Content.ReadFromJsonAsync<ConsentError>();

    if (error?.error == "consent_required")
    {
        // Trigger incremental consent in client app
        // This will redirect user to Microsoft Entra ID for consent
        throw new MsalUiRequiredException(error.error_description, error.scopes);
    }
}

Behandlung von nachgelagerten API-Fehlern

Ordnen Sie nachgeschaltete API-Fehlerantworten den entsprechenden HTTP-Statuscodes für Ihre Aufrufer zu.

[HttpGet("data")]
public async Task<ActionResult> GetData()
{
    try
    {
        var data = await _downstreamApi.GetForUserAsync<Data>("PartnerAPI", "api/data");
        return Ok(data);
    }
    catch (HttpRequestException ex) when (ex.StatusCode == HttpStatusCode.NotFound)
    {
        return NotFound("Resource not found in downstream service");
    }
    catch (HttpRequestException ex) when (ex.StatusCode == HttpStatusCode.BadRequest)
    {
        return BadRequest("Invalid request to downstream service");
    }
    catch (HttpRequestException ex)
    {
        _logger.LogError(ex, "Downstream API returned {StatusCode}", ex.StatusCode);
        return StatusCode(502, "Downstream service error");
    }
}

Implementieren in OWIN (.NET Framework)

Die folgenden Schritte zeigen, wie Sie eine OWIN-basierte Web-API konfigurieren, um nachgeschaltete APIs aufzurufen.

1. Konfigurieren von Startup.cs

Richten Sie OWIN-Middleware mit Microsoft.Identity.Web in Ihrer Startup Klasse ein.

using Microsoft.Identity.Web;
using Microsoft.Identity.Web.OWIN;
using Owin;

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
      OwinTokenAcquirerFactory factory = TokenAcquirerFactory.GetDefaultInstance<OwinTokenAcquirerFactory>();
      app.AddMicrosoftIdentityWebApi(factory);
      factory.Services
        .AddMicrosoftGraph()
        .AddDownstreamApis(factory.Configuration.GetSection("DownstreamAPIs"));
       factory.Build();
    }
}

2. Aufrufen der API von Controllern

Verwenden Sie Erweiterungsmethoden im Controller, um den Graph-Client, das Downstream-API-Hilfsprogramm oder den Anbieter des Autorisierungs-Headers abzurufen.

using Microsoft.Identity.Abstractions;
using Microsoft.Identity.Web;
using System.Web.Http;

[Authorize]
public class DataController : ApiController
{
    private readonly IDownstreamApi _downstreamApi;

    public DataController()
    {
      GraphServiceClient graphServiceClient = this.GetGraphServiceClient();
      var me = await graphServiceClient.Me.Request().GetAsync();

      // OR - Example calling a downstream directly with the IDownstreamApi helper (uses the
      // authorization header provider, encapsulates MSAL.NET)
      // downstreamApi won't be null if you added services.AddMicrosoftGraph()
      // in the Startup.auth.cs
      IDownstreamApi downstreamApi = this.GetDownstreamApi();
      var result = await downstreamApi.CallApiForUserAsync("DownstreamAPI");

      // OR - Get an authorization header (uses the token acquirer)
      IAuthorizationHeaderProvider authorizationHeaderProvider =
           this.GetAuthorizationHeaderProvider();
    }

    [HttpGet]
    [Route("api/data")]
    public async Task<IHttpActionResult> GetData()
    {
        var data = await _downstreamApi.GetForUserAsync<Data>(
            "PartnerAPI",
            options => options.RelativePath = "api/data",
            options => options.Scopes = new[] { "api://partner/read" });

        return Ok(data);
    }
}

Aufrufen mehrerer downstreamer APIs

Ihre API kann mehrere downstream-APIs in einer einzigen Anforderung aufrufen:

[HttpGet("dashboard")]
public async Task<ActionResult<Dashboard>> GetDashboard()
{
    try
    {
        // Call multiple APIs in parallel
        var userTask = _downstreamApi.GetForUserAsync<User>(
            "GraphAPI", "me");

        var dataTask = _downstreamApi.GetForUserAsync<Data>(
            "PartnerAPI", "api/data");

        var settingsTask = _downstreamApi.GetForUserAsync<Settings>(
            "PartnerAPI", "api/settings");

        await Task.WhenAll(userTask, dataTask, settingsTask);

        return Ok(new Dashboard
        {
            User = userTask.Result,
            Data = dataTask.Result,
            Settings = settingsTask.Result
        });
    }
    catch (Exception ex)
    {
        _logger.LogError(ex, "Failed to retrieve dashboard data");
        return StatusCode(500, "Failed to retrieve dashboard");
    }
}

Bewährte Methoden befolgen

Wenden Sie diese Empfehlungen an, um die Zuverlässigkeit und Sicherheit Ihrer API-zu-API-Aufrufe zu verbessern.

Verwenden des verteilten Caches in der Produktion

Vermeiden Sie In-Memory-Caches in Produktivumgebungen. Im folgenden Beispiel werden die beiden Ansätze verglichen.

//  Bad: In-memory cache in production
.AddInMemoryTokenCaches();

//  Good: Distributed cache in production
.AddDistributedTokenCaches();

Konfigurieren der Protokollierung

Fügen Sie eine strukturierte Protokollierung hinzu, um Authentifizierungs- und downstream-API-Ereignisse zu erfassen.

builder.Services.AddLogging(config =>
{
    config.AddConsole();
    config.AddApplicationInsights();
    config.SetMinimumLevel(LogLevel.Information);
});

Einstellen geeigneter Timeouts

Konfigurieren Sie HTTP-Clienttimeouts, um lange Wartezeiten für nicht reagierende downstream-Dienste zu verhindern.

builder.Services.AddDownstreamApi("PartnerAPI", options =>
{
    options.BaseUrl = "https://partnerapi.example.com";
    options.HttpClientName = "PartnerAPI";
});

builder.Services.AddHttpClient("PartnerAPI", client =>
{
    client.Timeout = TimeSpan.FromSeconds(30);
});

Überprüfen eingehender Token

Stellen Sie sicher, dass Ihre API Token ordnungsgemäß überprüft. Der folgende Code bindet die Tokenüberprüfungseinstellungen aus der Konfiguration.

builder.Services.AddMicrosoftIdentityWebApi(options =>
{
    builder.Configuration.Bind("AzureAd", options);
});

Häufige Fehler beheben

Verwenden Sie diese Lösungen, um häufig auftretende Probleme mit dem OBO-Fluss zu beheben.

Auflösen von "AADSTS50013: Assertion hat die Signaturprüfung nicht bestanden"

Ursache: Der geheime Clientschlüssel oder das Zertifikat ist in der App-Registrierung Ihrer API falsch konfiguriert.

Solution: Stellen Sie sicher, dass die Clientanmeldeinformationen in appsettings.json der Microsoft Entra ID App-Registrierung entsprechen.

Auflösen von "AADSTS65001: Benutzer oder Administrator hat nicht zugestimmt"

Ursache: Der Benutzer hat nicht zugestimmt, dass Ihre API die nachgeschaltete API aufruft.

Lösung: Geben Sie den richtigen Fehler an die Client-App zurück und lösen Sie den Zustimmungsfluss im Client aus.

Beheben von "AADSTS500133: Assertion liegt nicht innerhalb des gültigen Zeitbereichs"

Ursache: Uhrenabweichung zwischen Servern oder ein abgelaufenes Token.

Lösung:

  • Serveruhren synchronisieren
  • Überprüfung der Token-Gültigkeit
  • Sicherstellen, dass der Tokencache ordnungsgemäß funktioniert

Auflösen des OBO-Tokens, das nicht zwischengespeichert wurde

Ursache: Der verteilte Cache ist nicht konfiguriert, oder es gibt Cacheschlüsselprobleme.

Lösung:

  • Überprüfen der Verbindung mit verteilten Caches
  • Überprüfen Sie, ob oid und tid Behauptungen im eingehenden Token vorhanden sind.
  • Aktivieren der Debugprotokollierung zum Anzeigen von Cachevorgängen

Mehrere API-Instanzen beheben, die keinen Cache teilen

Ursache: Die API verwendet den Speichercache anstelle des verteilten Caches.

Solution: Wechseln zum verteilten Cache (Redis, SQL Server, Cosmos DB).

Detaillierte Diagnose: Siehe Protokollierungs- und Diagnosehandbuch für Korrelations-IDs, Tokencachedebugging, PII-Protokollierungskonfiguration und umfassende Problembehandlungsworkflows.


Nächste Schritte: Erfahren Sie mehr über Calling Microsoft Graph oder custom APIs mit spezialisierten Integrationsmustern.