Bereitstellen von Web-Apps hinter Proxys und Gateways

Wenn Sie ASP.NET Core-Web-Apps mit Microsoft.Identity.Web hinter Reverse-Proxys, Load Balancern oder Azure-Gateways bereitstellen, müssen Sie Redirect-URIs korrekt behandeln, damit Authentifizierungsrückrufe erfolgreich sind.

Umleitungs-URIs werden in Proxyszenarien komplex, da:

  • Microsoft Entra ID leitet Benutzer nach der Anmeldung an den konfigurierten Umleitungs-URI weiter.
  • Proxys ändern den Anforderungskontext - Schema (HTTP/HTTPS), Host, Port, Pfad
  • Redirect-URI muss exakt übereinstimmen, was in Microsoft Entra ID registriert ist
  • CallbackPath muss über den Proxy funktionieren.

Identifizieren allgemeiner Proxyszenarien

Die folgenden Szenarien veranschaulichen, wie sich unterschiedliche Proxyarchitekturen auf die Umleitungs-URI-Konstruktion auswirken.

Azure Application Gateway

Anwendungsfall: Regionaler Lastenausgleich, WAF, SSL-Beendigung

Auswirkungen auf umleitungs-URI:

  • Gateway-URL: https://gateway.contoso.com/myapp
  • Back-End-URL: http://backend.internal/
  • Microsoft Entra ID Umleitung: https://gateway.contoso.com/myapp/signin-oidc

Azure Front Door

Anwendungsfall: Globale Verteilung, CDN, mehrere Regionen

Auswirkungen auf umleitungs-URI:

  • URL der Tür: https://myapp.azurefd.net
  • Backend-URLs: https://app-eastus.azurewebsites.net, https://app-westus.azurewebsites.net
  • Microsoft Entra ID Umleitung: https://myapp.azurefd.net/signin-oidc

Lokaler Reverseproxy

Anwendungsfall: Unternehmensnetzwerk, bestehende Infrastruktur

Auswirkungen auf umleitungs-URI:

  • Proxy-URL: https://apps.corp.com/myapp
  • Back-End-URL: http://appserver:5000/
  • Microsoft Entra ID Umleitung: https://apps.corp.com/myapp/signin-oidc

Kubernetes-Ingress

Anwendungsfall: Container-Orchestrierung, Microservices

Auswirkungen auf umleitungs-URI:

  • Eingangs-URL: https://apps.k8s.com/webapp
  • Dienst-URL: http://webapp-service.default.svc.cluster.local
  • Microsoft Entra ID Umleitung: https://apps.k8s.com/webapp/signin-oidc

Konfigurieren Sie weitergeleitete Header

Weitergeleitete Header sind für Proxybereitstellungen unerlässlich. Ohne sie erstellt die Back-End-App falsche Umleitungs-URIs.

Warum weitergeleitete Kopfzeilen wichtig sind

Web-Apps benötigen richtigen Anforderungskontext für:

  1. Erstellen absoluter Umleitungs-URIs für Microsoft Entra ID
  2. Überprüfen der Eingehenden Authentifizierungsantwort
  3. Generieren korrekter Abmelde-URIs
  4. Behandeln der HTTPS-Anforderungserzwingung

Ohne weitergeleitete Header-Middleware:

User visits: https://gateway.contoso.com/myapp
Backend sees: http://localhost:5000/
Redirect URI built: http://localhost:5000/signin-oidc  Wrong!
Microsoft Entra ID redirects to: https://gateway.contoso.com/myapp/signin-oidc
Backend doesn't recognize it: Error!

Mit weitergeleiteter Header-Middleware:

User visits: https://gateway.contoso.com/myapp
Backend sees forwarded headers: X-Forwarded-Proto: https, X-Forwarded-Host: gateway.contoso.com
Redirect URI built: https://gateway.contoso.com/myapp/signin-oidc  Correct!
Microsoft Entra ID redirects to: https://gateway.contoso.com/myapp/signin-oidc
Backend recognizes it: Success!

Einrichten grundlegender weitergeleiteter Kopfzeilen

Konfigurieren Sie die Middleware für weitergeleitete Header vor der Authentifizierung in Program.cs.

using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.Identity.Web;

var builder = WebApplication.CreateBuilder(args);

// CRITICAL: Configure forwarded headers BEFORE authentication
builder.Services.Configure<ForwardedHeadersOptions>(options =>
{
    options.ForwardedHeaders = ForwardedHeaders.XForwardedFor |
                                ForwardedHeaders.XForwardedProto |
                                ForwardedHeaders.XForwardedHost;

    // Accept headers from any source (proxy/gateway)
    options.KnownNetworks.Clear();
    options.KnownProxies.Clear();

    // Standard header names
    options.ForwardedForHeaderName = "X-Forwarded-For";
    options.ForwardedProtoHeaderName = "X-Forwarded-Proto";
    options.ForwardedHostHeaderName = "X-Forwarded-Host";
});

// Authentication
builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"));

builder.Services.AddRazorPages();

var app = builder.Build();

// CRITICAL: Use forwarded headers BEFORE authentication
app.UseForwardedHeaders();

// Only enforce HTTPS if you're sure the proxy forwards the scheme correctly
if (!app.Environment.IsDevelopment())
{
    app.UseHttpsRedirection();
}

app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.MapRazorPages();

app.Run();

Fügen Sie die Authentifizierungseinstellungen zu appsettings.json:

{
  "AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "TenantId": "your-tenant-id",
    "ClientId": "your-client-id",
    "ClientSecret": "your-client-secret",
    "CallbackPath": "/signin-oidc"
  }
}

Registrieren Sie die Gateway-URL als Umleitungs-URI in der Microsoft Entra App-Registrierung:

https://gateway.contoso.com/myapp/signin-oidc

Verarbeitung von pfadbasiertem Routing

Verwenden Sie pfadbasiertes Routing, wenn ein Proxy Anfragen ein Pfadpräfix hinzufügt.

Problem: Proxy fügt Pfadpräfix hinzu

Szenario:

  • Proxy-URL: https://apps.contoso.com/webapp1
  • Back-End-URL: http://backend:5000/
  • Back-End weiß nur über /, nicht /webapp1

Legen Sie diese Einstellung UsePathBase fest, um die App über das Pfadpräfix zu informieren:

var app = builder.Build();

// Tell the app it's hosted at a path prefix
app.UsePathBase("/webapp1");

app.UseForwardedHeaders();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.MapRazorPages();

app.Run();

Funktionsweise:

  • HttpContext.Request.Path entfernt das /webapp1 Präfix für routing
  • HttpContext.Request.PathBase enthält /webapp1
  • Die Verknüpfungsgenerierung enthält automatisch die Pfadbasis.
  • Umleitungs-URIs enthalten automatisch die Pfadbasis

Registrieren Sie den vollständigen Pfad in der Microsoft Entra App-Registrierung:

https://apps.contoso.com/webapp1/signin-oidc

Lösung 2: Proxy-Pfad neu schreiben

Einige Proxys entfernen das Pfadpräfix vor der Weiterleitung. Konfigurieren Sie den Proxy, um den Pfad umzuschreiben und die ursprünglichen Header weiterzuleiten:

NGINX-Konfiguration:

location /webapp1/ {
    proxy_pass http://backend:5000/;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header X-Original-URL $request_uri;
}

Wenn der Proxy das Präfix entfernt, wird in der Anwendung keine PathBase benötigt:

// No PathBase needed if proxy strips the prefix
app.UseForwardedHeaders();

Registrieren Sie die Proxy-URL in der Microsoft Entra-App-Registrierung:

https://apps.contoso.com/webapp1/signin-oidc

Lösung 3: Benutzerdefinierte Middleware für dynamische PathBase

Wenn die Pfadbasis je nach Umgebung variiert, lesen Sie sie aus der Konfiguration, oder erkennen Sie sie aus Anforderungsheadern:

// Read path base from configuration or headers
var pathBase = builder.Configuration["PathBase"];
if (!string.IsNullOrEmpty(pathBase))
{
    app.UsePathBase(pathBase);
}

// Or detect from X-Forwarded-Prefix header
app.Use((context, next) =>
{
    var forwardedPrefix = context.Request.Headers["X-Forwarded-Prefix"].ToString();
    if (!string.IsNullOrEmpty(forwardedPrefix))
    {
        context.Request.PathBase = forwardedPrefix;
    }
    return next();
});

app.UseForwardedHeaders();

SSL/TLS-Terminierung bearbeiten

Wenn ein Proxy SSL/TLS beendet, empfängt das Back-End HTTP-Anforderungen und erstellt falsche Umleitungs-URIs, es sei denn, Sie konfigurieren die Headerweiterleitung.

Problem: Proxy unterbricht HTTPS

Szenario:

  • Der Benutzer stellt über HTTPS eine Verbindung mit proxy bereit.
  • Proxy verbindet sich über HTTP mit dem Backend.
  • Back-End erstellt HTTP-Umleitungs-URIs (falsch!)

Lösung: X-Forwarded-Proto Header

Konfigurieren Sie den Proxy, um den X-Forwarded-Proto Header zu senden, damit das Back-End das ursprüngliche Schema kennt.

Proxykonfiguration (NGINX):

location / {
    proxy_pass http://backend:5000;
    proxy_set_header X-Forwarded-Proto $scheme;  # Critical!
    proxy_set_header X-Forwarded-Host $host;
}

Konfigurieren Sie die App so, dass der weitergeleitete Proto-Header gelesen wird, und legen Sie das Anforderungsschema fest:

builder.Services.Configure<ForwardedHeadersOptions>(options =>
{
    options.ForwardedHeaders = ForwardedHeaders.XForwardedProto |
                                ForwardedHeaders.XForwardedHost;
    options.KnownNetworks.Clear();
    options.KnownProxies.Clear();
});

var app = builder.Build();

app.UseForwardedHeaders(); // Reads X-Forwarded-Proto and sets Request.Scheme = "https"

// HTTPS redirection becomes safe
app.UseHttpsRedirection(); // Won't create infinite redirect loop

app.UseAuthentication();

Häufig auftretender Fehler: HTTPS-Umleitungsschleife

Problem:

// Without UseForwardedHeaders()
app.UseHttpsRedirection(); // Sees Request.Scheme = "http", redirects to HTTPS
// User gets infinite redirect loop!

Lösung:

// WITH UseForwardedHeaders()
app.UseForwardedHeaders(); // Sets Request.Scheme = "https" from X-Forwarded-Proto
app.UseHttpsRedirection(); // Sees HTTPS, no redirect needed 

Konfigurieren benutzerdefinierter Domänen

Verwenden Sie eine benutzerdefinierte Domäne mit Azure Front Door, um Benutzern beim Weiterleiten von Datenverkehr an Back-End-Dienste eine Branding-URL zu präsentieren.

Szenario: Benutzerdefinierte Domäne über Azure Front Door

Architektur:

  • Benutzerdefinierte Domäne: https://myapp.contoso.com
  • Front Door: https://myapp.azurefd.net (Backend-Ursprung)
  • Azure Web App: https://myapp-backend.azurewebsites.net

Frontdoor-Konfiguration:

  1. Hinzufügen einer benutzerdefinierten Domäne myapp.contoso.com zu Front Door
  2. Konfigurieren eines SSL-Zertifikats (Front Door verwaltet oder benutzerdefiniert)
  3. Festlegen des Back-End-Pools auf myapp-backend.azurewebsites.net
  4. Nur HTTPS aktivieren

Konfigurieren Sie die App so, dass weitergeleitete Kopfzeilen von Front Door akzeptiert werden:

// No special configuration needed if headers are forwarded correctly
builder.Services.Configure<ForwardedHeadersOptions>(options =>
{
    options.ForwardedHeaders = ForwardedHeaders.XForwardedFor |
                                ForwardedHeaders.XForwardedProto |
                                ForwardedHeaders.XForwardedHost;
    options.KnownNetworks.Clear();
    options.KnownProxies.Clear();
});

Registrieren Sie sowohl die Anmelde- als auch die Abmelderückruf-URIs in der Microsoft Entra-App-Registrierung:

https://myapp.contoso.com/signin-oidc
https://myapp.contoso.com/signout-callback-oidc

Verwenden Sie den folgenden Diagnoseendpunkt, um den Umleitungs-URI zu überprüfen, den die App generiert:

// In a controller or page
public IActionResult TestRedirectUri()
{
    var request = HttpContext.Request;
    var scheme = request.Scheme; // Should be "https"
    var host = request.Host.Value; // Should be "myapp.contoso.com"
    var pathBase = request.PathBase.Value; // Should be "" or your path base
    var path = "/signin-oidc";

    var redirectUri = $"{scheme}://{host}{pathBase}{path}";
    // Expected: https://myapp.contoso.com/signin-oidc

    return Content($"Redirect URI would be: {redirectUri}");
}

Registrieren mehrerer Umleitungs-URIs

Wenn Ihre App in verschiedenen Umgebungen hinter unterschiedlichen Gateways ausgeführt wird, registrieren Sie einen Umleitungs-URI für jedes einzelne Gateway.

Problem: Gleiche App, mehrere Gateways

Szenario:

  • Produktion: https://app.contoso.com (Eingangstür)
  • Staging: https://app-staging.azurewebsites.net (Direkt)
  • Entwicklung: https://localhost:5001 (lokal)

Lösung: Registrieren aller Umleitungs-URIs

Fügen Sie jeden umgebungsspezifischen Umleitungs-URI zur Microsoft Entra App-Registrierung hinzu:

https://app.contoso.com/signin-oidc
https://app-staging.azurewebsites.net/signin-oidc
https://localhost:5001/signin-oidc

Der Anwendungscode erfordert keine umgebungsspezifischen Änderungen:

var app = builder.Build();

app.UseForwardedHeaders(); // Handles proxy scenarios
app.UseAuthentication(); // Builds correct redirect URI based on request context

Funktionsweise:

  • Die Anwendung erstellt dynamische Umleitungs-URI basierend auf eingehender Anforderung
  • HttpContext.Request.Scheme, Host und PathBase bestimmen den URI
  • Solange sie in Microsoft Entra ID registriert ist, ist die Authentifizierung erfolgreich.

Konfigurieren von Azure Application Gateway

Dieser Abschnitt enthält ein vollständiges Konfigurationsbeispiel für die Bereitstellung einer Web-App hinter Azure Application Gateway mit pfadbasiertem Routing.

Vollständiges Beispiel mit pfadbasiertem Routing

Anwendungsgatewayeinstellungen:

Backend-Pool:

  • Ziel: backend.azurewebsites.net oder IP-Adresse

HTTP-Einstellungen:

  • Protokoll: HTTPS (empfohlen) oder HTTP
  • Port: 443 oder 80
  • Deaktivieren des Backend-Pfads: Nein
  • Benutzerdefinierte Probe: Ja

Gesundheitsprüfung:

  • Protokoll: HTTPS oder HTTP
  • Host: Leer lassen (verwendet den Hostnamen des Back-End-Pools)
  • Pfad: /health (muss anonymer Endpunkt sein)
  • Intervall: 30 Sekunden

Routingregel:

  • Name: webapp-rule
  • Listener: HTTPS-Listener am Port 443
  • Backend-Pool: Ihr Backend-Pool
  • HTTP-Einstellungen: Ihre HTTP-Einstellungen

Konfigurieren Sie die Anwendung so, dass weitergeleitete Header, Authentifizierung und Integritätssonden behandelt werden:

using Microsoft.AspNetCore.HttpOverrides;

var builder = WebApplication.CreateBuilder(args);

// Forwarded headers for Application Gateway
builder.Services.Configure<ForwardedHeadersOptions>(options =>
{
    options.ForwardedHeaders = ForwardedHeaders.XForwardedFor |
                                ForwardedHeaders.XForwardedProto |
                                ForwardedHeaders.XForwardedHost;
    options.KnownNetworks.Clear();
    options.KnownProxies.Clear();
});

// Authentication
builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"));

// Health checks (for Application Gateway probe)
builder.Services.AddHealthChecks();

builder.Services.AddRazorPages();

var app = builder.Build();

// Health endpoint BEFORE authentication (critical for gateway probes)
app.MapHealthChecks("/health").AllowAnonymous();

// Middleware order
app.UseForwardedHeaders();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.MapRazorPages();

app.Run();

Fügen Sie die Authentifizierungseinstellungen zu appsettings.json:

{
  "AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "TenantId": "your-tenant-id",
    "ClientId": "your-client-id",
    "ClientSecret": "your-client-secret",
    "CallbackPath": "/signin-oidc"
  }
}

Registrieren Sie die Redirect-URIs für Gateways in der Microsoft Entra App-Registrierung.

https://gateway.contoso.com/signin-oidc
https://gateway.contoso.com/signout-callback-oidc

Konfigurieren von Azure Front Door

In diesem Abschnitt wird gezeigt, wie Sie eine Mehrregion-Web-App hinter Azure Front Door mit konsistenter Authentifizierung bereitstellen.

Bereitstellung mehrregionaler Webanwendungen

Szenario:

  • Front Door: https://app.azurefd.net (globaler Endpunkt)
  • Ost-USA: https://app-eastus.azurewebsites.net
  • WEST-USA: https://app-westus.azurewebsites.net
  • Benutzer, die an die nächste Region weitergeleitet wurden

Frontdoor-Konfiguration:

Ursprungsgruppe:

  • Name: webapp-origins
  • Gesundheitsüberprüfung: /health
  • Lastenausgleich: Latenzbasiert

Ursprünge:

  1. app-eastus.azurewebsites.net (Priorität 1)
  2. app-westus.azurewebsites.net (Priorität 1)

Route:

  • Pfad: /*
  • Weiterleitungsprotokoll: Nur HTTPS
  • Herkunftsgruppe: webapp-origins

Stellen Sie denselben Anwendungscode in beiden Regionen bereit:

using Microsoft.AspNetCore.HttpOverrides;

var builder = WebApplication.CreateBuilder(args);

// Forwarded headers for Front Door
builder.Services.Configure<ForwardedHeadersOptions>(options =>
{
    options.ForwardedHeaders = ForwardedHeaders.XForwardedFor |
                                ForwardedHeaders.XForwardedProto |
                                ForwardedHeaders.XForwardedHost;
    options.KnownNetworks.Clear();
    options.KnownProxies.Clear();
});

builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"));

builder.Services.AddHealthChecks();
builder.Services.AddRazorPages();

var app = builder.Build();

// Health check for Front Door probe
app.MapHealthChecks("/health").AllowAnonymous();

app.UseForwardedHeaders();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.MapRazorPages();

app.Run();

Beide Regionen teilen die gleiche Microsoft Entra App-Registrierung mit dem gleichen Umleitungs-URI:

https://app.azurefd.net/signin-oidc
https://app.azurefd.net/signout-callback-oidc

Warum es funktioniert:

  • Front Door URL ist in allen Regionen konsistent
  • Weitergeleitete Header stellen sicher, dass die Backend-Builds den korrekten Umleitungs-URI erstellen.
  • Tokenerwerb erfolgt im regionalen Back-End
  • Verteilter Tokencache (Redis) teilt Token über Regionen hinweg

Häufige Probleme beheben

In diesem Abschnitt werden die häufigsten Authentifizierungsfehler in Proxybereitstellungen und deren Behebung behandelt.

Problem: Fehler "Umleitungs-URI stimmt nicht überein"

Symptome:

AADSTS50011: The redirect URI 'http://localhost:5000/signin-oidc'
specified in the request does not match the redirect URIs configured
for the application 'your-app-id'.

Mögliche Ursachen:

  1. Fehlende Middleware für weitergeleitete Header

    // Fix: Add BEFORE authentication
    app.UseForwardedHeaders();
    app.UseAuthentication();
    
  2. Falsche Umleitungs-URI, die in Microsoft Entra ID registriert ist

    • Überprüfen registrierter URIs im Azure Portal
    • Sicherstellen von HTTPS (nicht HTTP) für die Produktion
    • Sicherstellen von Host-Übereinstimmungen (einschließlich Port, falls nicht standardmäßig)
    • Stellen Sie sicher, dass der Pfad, falls zutreffend, PathBase enthält.
  3. Proxy leitet Header nicht weiter

    • Überprüfen der Proxykonfiguration
    • Überprüfen Sie, dass X-Forwarded-Proto und X-Forwarded-Host festgelegt sind.
    • Testen mit curl: curl -H "X-Forwarded-Proto: https" -H "X-Forwarded-Host: gateway.com" http://backend:5000/
  4. PathBase nicht konfiguriert

    // If proxy adds /myapp prefix, add this:
    app.UsePathBase("/myapp");
    

Fügen Sie die folgende Diagnose-Middleware hinzu, um den Umleitungs-URI zu protokollieren, den die App erstellt:

// Add this middleware to log the redirect URI being built
app.Use(async (context, next) =>
{
    var logger = context.RequestServices.GetRequiredService<ILogger<Program>>();
    logger.LogInformation(
        "Request: Scheme={Scheme}, Host={Host}, PathBase={PathBase}, Path={Path}",
        context.Request.Scheme,
        context.Request.Host,
        context.Request.PathBase,
        context.Request.Path);

    await next();
});

Problem: Die Authentifizierung funktioniert lokal, aber nicht hinter Proxy.

Symptome:

  • Anmeldung funktioniert bei localhost:5001
  • Anmeldung schlägt fehl gateway.contoso.com
  • Fehler: Umleitungs-URI-Nichtübereinstimmung oder Korrelationsfehler

Lösungscheckliste:

  1. Weitergeleitete Header konfiguriert und zuerst verwendet
app.UseForwardedHeaders(); // Must be first!
  1. Proxy leitet erforderliche Header weiter
  • X-Forwarded-Proto: https
  • X-Forwarded-Host: gateway.contoso.com
  • Optional: X-Forwarded-Prefix für Pfadbasis
  1. Redirect-URI, die in Microsoft Entra ID registriert ist
  • https://gateway.contoso.com/signin-oidc
  1. PathBase ist konfiguriert, falls erforderlich
app.UsePathBase("/myapp"); // If proxy adds prefix
  1. HTTPS wird ordnungsgemäß erzwungen
app.UseForwardedHeaders(); // Reads X-Forwarded-Proto first
app.UseHttpsRedirection(); // Then enforces HTTPS

Problem: Sign-Out schlägt fehl oder leitet zu einer falschen URL um.

Symptome:

  • Anmeldung funktioniert
  • Abmeldeweiterleitungen zu falscher URL (localhost, http://, falscher Host)

Stellen Sie den PostLogoutRedirectUri anhand des weitergeleiteten Anforderungskontexts ein.

// Ensure PostLogoutRedirectUri uses correct base URL
builder.Services.Configure<OpenIdConnectOptions>(
    OpenIdConnectDefaults.AuthenticationScheme,
    options =>
    {
        options.Events.OnRedirectToIdentityProviderForSignOut = context =>
        {
            // Build correct post-logout redirect URI
            var request = context.HttpContext.Request;
            var postLogoutUri = $"{request.Scheme}://{request.Host}{request.PathBase}/signout-callback-oidc";

            context.ProtocolMessage.PostLogoutRedirectUri = postLogoutUri;
            return Task.CompletedTask;
        };
    });

Registrieren Sie die Abmelderückruf-URI in der Microsoft Entra-App-Registrierung:

https://gateway.contoso.com/signout-callback-oidc

Problem: Endlosumleitungsschleife

Symptome:

  • Der Browser leitet zwischen der App und Microsoft Entra ID weiter
  • Anmeldung nie abgeschlossen

Mögliche Ursachen:

  1. HTTPS-Umleitung vor weitergeleiteten Headern

    // WRONG ORDER:
    app.UseHttpsRedirection(); // Sees HTTP, redirects to HTTPS
    app.UseForwardedHeaders(); // Too late!
    
    // CORRECT ORDER:
    app.UseForwardedHeaders(); // Sets scheme to HTTPS
    app.UseHttpsRedirection(); // Sees HTTPS, no redirect
    
  2. Cookieeinstellungen, die nicht mit Proxy kompatibel sind

    builder.Services.Configure<CookiePolicyOptions>(options =>
    {
        options.MinimumSameSitePolicy = SameSiteMode.None; // For cross-site scenarios
        options.Secure = CookieSecurePolicy.Always; // Requires HTTPS
    });
    
  3. Nichtübereinstimmung der Cookiedomäne

    // If subdomain issues, may need to set cookie domain
    builder.Services.ConfigureApplicationCookie(options =>
    {
        options.Cookie.Domain = ".contoso.com"; // Allows cookies across subdomains
    });
    

Bewährte Methoden befolgen

Wenden Sie diese Methoden auf jede Proxybereitstellung an, um häufige Fallstricke zu vermeiden.

1. Verwenden Sie immer weitergeleitete Header-Middleware

// For ANY deployment behind proxy/gateway/load balancer
builder.Services.Configure<ForwardedHeadersOptions>(options =>
{
    options.ForwardedHeaders = ForwardedHeaders.XForwardedFor |
                                ForwardedHeaders.XForwardedProto |
                                ForwardedHeaders.XForwardedHost;
    options.KnownNetworks.Clear();
    options.KnownProxies.Clear();
});

var app = builder.Build();
app.UseForwardedHeaders(); // FIRST middleware!

2. Registrieren aller Umleitungs-URIs

Registrieren Sie Umleitungs-URIs für jede Umgebung in der Microsoft Entra-App-Registrierung:

Production:  https://app.contoso.com/signin-oidc
Staging:     https://app-staging.azurewebsites.net/signin-oidc
Development: https://localhost:5001/signin-oidc

3. Testumleitungs-URI-Generierung

Fügen Sie einen Entwicklungsdiagnoseendpunkt hinzu, um den Umleitungs-URI zu überprüfen:

// Add diagnostics endpoint (development only!)
if (app.Environment.IsDevelopment())
{
    app.MapGet("/debug/redirect-uri", (HttpContext context) =>
    {
        var redirectUri = $"{context.Request.Scheme}://{context.Request.Host}{context.Request.PathBase}/signin-oidc";
        return Results.Ok(new { redirectUri });
    }).AllowAnonymous();
}

4. Gesundheitsendpunkt für Gateway-Prüfungen

Ordnen Sie den Integritätsendpunkt vor der Authentifizierungs-Middleware zu, damit Gatewaysonden keine Anmeldung erfordern:

// Must be BEFORE authentication middleware
app.MapHealthChecks("/health").AllowAnonymous();

app.UseAuthentication(); // Health endpoint bypasses this

5. Verteilter Tokencache für mehrere Regionen

Verwenden Sie einen verteilten Cache wie Redis, um Token über Regionen hinweg zu teilen.

// Use Redis for token cache across regions
builder.Services.AddStackExchangeRedisCache(options =>
{
    options.Configuration = builder.Configuration["Redis:ConnectionString"];
    options.InstanceName = "TokenCache_";
});

builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"))
    .EnableTokenAcquisitionToCallDownstreamApi()
    .AddDistributedTokenCaches();

6. Konfigurieren der Protokollierung für die Problembehandlung

Aktivieren Sie das Debug-Logging für Microsoft.Identity.Web und weitergeleitete Header zur Diagnose von Problemen.

builder.Logging.AddConfiguration(builder.Configuration.GetSection("Logging"));

// In appsettings.json
{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning",
      "Microsoft.Identity.Web": "Debug",
      "Microsoft.AspNetCore.HttpOverrides": "Debug"
    }
  }
}

Ein vollständiges Beispiel überprüfen

In diesem End-to-End-Beispiel wird eine Web-App hinter Azure Application Gateway mit Microsoft Graph Integration bereitgestellt.

Anwendungscode

Das folgende Program.cs konfiguriert weitergeleitete Header, Authentifizierung mit Microsoft Graph und Gesundheitsprüfungen.

using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.Identity.Web;
using Microsoft.Identity.Web.UI;

var builder = WebApplication.CreateBuilder(args);

// Forwarded headers for Application Gateway
builder.Services.Configure<ForwardedHeadersOptions>(options =>
{
    options.ForwardedHeaders = ForwardedHeaders.XForwardedFor |
                                ForwardedHeaders.XForwardedProto |
                                ForwardedHeaders.XForwardedHost;
    options.KnownNetworks.Clear();
    options.KnownProxies.Clear();
});

// Authentication
builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"))
    .EnableTokenAcquisitionToCallDownstreamApi()
    .AddMicrosoftGraph()
    .AddInMemoryTokenCaches();

// Health checks
builder.Services.AddHealthChecks();

// Add Microsoft Identity UI for sign-in/sign-out
builder.Services.AddRazorPages()
    .AddMicrosoftIdentityUI();

var app = builder.Build();

// Health endpoint (before authentication)
app.MapHealthChecks("/health").AllowAnonymous();

// Middleware order is critical
app.UseForwardedHeaders();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.MapRazorPages();
app.MapControllers();

app.Run();

Hinzufügen der Authentifizierungs- und Protokollierungskonfiguration zu appsettings.json:

{
  "AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "TenantId": "your-tenant-id",
    "ClientId": "your-client-id",
    "ClientSecret": "your-client-secret",
    "CallbackPath": "/signin-oidc",
    "SignedOutCallbackPath": "/signout-callback-oidc"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning",
      "Microsoft.Identity.Web": "Information",
      "Microsoft.AspNetCore.HttpOverrides": "Debug"
    }
  }
}

Registrieren Sie die folgenden URIs in der Microsoft Entra-App-Registrierung:

Umleitungs-URIs:

https://gateway.contoso.com/signin-oidc
https://gateway.contoso.com/signout-callback-oidc

Logout-URL des Frontkanals:

https://gateway.contoso.com/signout-oidc

Konfiguration des Anwendungsgateways

Konfigurieren Sie die folgenden Anwendungsgatewayressourcen:

Backend-Pool:

  • Name: webapp-backend
  • Ziel: webapp.azurewebsites.net oder IP-Adressen

HTTP-Einstellungen:

  • Name: webapp-https-settings
  • Protokoll: HTTPS
  • Port: 443
  • Deaktivieren des Backend-Pfads: Nein
  • Hostname aus Back-End-Ziel auswählen: Ja
  • Benutzerdefinierte Probe: Ja → webapp-health-probe

Gesundheitsprüfung:

  • Name: webapp-health-probe
  • Protokoll: HTTPS
  • Auswählen des Hostnamens aus den Back-End-HTTP-Einstellungen: Ja
  • Pfad: /health
  • Intervall: 30 Sekunden
  • Ungesunde Schwelle: 3

Listener:

  • Name: webapp-listener
  • Front-End-IP: Öffentlich
  • Protokoll: HTTPS
  • Port: 443
  • SSL-Zertifikat: Ihr Zertifikat

Routingregel:

  • Name: webapp-rule
  • Regeltyp: Grundlegend
  • Abhörer: webapp-listener
  • Backend-Ziel: webapp-backend
  • HTTP-Einstellungen: webapp-https-settings