Implementare applicazioni web dietro proxy e gateway

Quando distribuisci app Web ASP.NET Core con Microsoft.Identity.Web dietro proxy inversi, servizi di bilanciamento del carico o gateway di Azure, bisogna gestire le URI di reindirizzamento correttamente per consentire il corretto funzionamento dei callback di autenticazione.

Gli URI di reindirizzamento diventano complessi negli scenari proxy perché:

  • Microsoft Entra ID reindirizza gli utenti all'URI di reindirizzamento configurato dopo l'accesso
  • I proxy modificano il contesto della richiesta - schema (HTTP/HTTPS), host, porta, percorso
  • L'URI di reindirizzamento deve corrispondere esattamente a quello che è registrato in Microsoft Entra ID
  • CallbackPath deve funzionare tramite il proxy

Identificare scenari proxy comuni

Gli scenari seguenti illustrano in che modo le diverse architetture proxy influiscono sulla costruzione dell'URI di reindirizzamento.

gateway applicazione di Azure

Caso d'uso: Bilanciamento del carico a livello di area, WAF, terminazione SSL

Impatto sull'URI di reindirizzamento:

  • URL del gateway: https://gateway.contoso.com/myapp
  • URL back-end: http://backend.internal/
  • Microsoft Entra ID reindirizzamento: https://gateway.contoso.com/myapp/signin-oidc

Frontdoor di Azure

Caso d'uso: Distribuzione globale, rete CDN, più aree

Impatto sull'URI di reindirizzamento:

  • URL del Front Door: https://myapp.azurefd.net
  • URL backend: https://app-eastus.azurewebsites.net, https://app-westus.azurewebsites.net
  • Microsoft Entra ID reindirizzamento: https://myapp.azurefd.net/signin-oidc

Proxy inverso locale

Caso d'uso: Rete aziendale, infrastruttura esistente

Impatto sull'URI di reindirizzamento:

  • URL proxy: https://apps.corp.com/myapp
  • URL back-end: http://appserver:5000/
  • Microsoft Entra ID reindirizzamento: https://apps.corp.com/myapp/signin-oidc

Ingresso di Kubernetes

Caso d'uso: Orchestrazione dei contenitori, microservizi

Impatto sull'URI di reindirizzamento:

  • URL d'ingresso: https://apps.k8s.com/webapp
  • URL servizio: http://webapp-service.default.svc.cluster.local
  • Microsoft Entra ID reindirizzamento: https://apps.k8s.com/webapp/signin-oidc

Configurare le intestazioni inoltrate

Le intestazioni inoltrate sono fondamentali nelle implementazioni proxy. Senza di essi, l'app back-end compila URI di reindirizzamento non corretti.

Perché le intestazioni inoltrate sono importanti

Per le app Web è necessario un contesto di richiesta corretto per:

  1. Creare URI di reindirizzamento assoluti per Microsoft Entra ID
  2. Convalidare la risposta di autenticazione in ingresso
  3. Generare URI di logout corretti
  4. Gestire l'imposizione dei requisiti HTTPS

Senza le intestazioni inoltrate nel 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!

Con il middleware delle intestazioni inoltrate:

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!

Configura le intestazioni di inoltro di base

Configura il middleware delle intestazioni inoltrate in Program.cs prima dell'autenticazione:

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();

Aggiungere le impostazioni di autenticazione a appsettings.json:

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

Registrare l'URL del gateway come URI di reindirizzamento nella registrazione dell'app Microsoft Entra:

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

Gestire il routing basato sul percorso

Usare il routing basato sul percorso quando un proxy aggiunge un prefisso di percorso alle richieste.

Problema: il proxy aggiunge il prefisso del percorso

Scenario:

  • URL proxy: https://apps.contoso.com/webapp1
  • URL back-end: http://backend:5000/
  • Il back-end conosce solo /, non /webapp1

Impostare UsePathBase per indicare all'app il prefisso del percorso:

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();

Funzionamento:

  • HttpContext.Request.Path rimuove il prefisso del /webapp1 routing
  • HttpContext.Request.PathBase contiene /webapp1
  • La generazione di collegamenti include automaticamente la base del percorso
  • Gli URI di reindirizzamento includono automaticamente la base del percorso

Registrare il percorso completo nella registrazione dell'app Microsoft Entra:

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

Soluzione 2: Il proxy riscrive il percorso

Alcuni proxy eliminano il prefisso del percorso prima dell'inoltro. Configurare il proxy per riscrivere il percorso e inoltrare le intestazioni originali:

Configurazione NGINX:

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;
}

Quando il proxy rimuove il prefisso, non è necessario PathBase nell'applicazione:

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

Registrare l'URL rivolto al proxy nella registrazione dell'app Microsoft Entra:

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

Soluzione 3: middleware personalizzato per PathBase dinamico

Quando la base del percorso varia in base all'ambiente, leggerla dalla configurazione o rilevarla dalle intestazioni della richiesta:

// 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();

Gestire la terminazione SSL/TLS

Quando un proxy termina SSL/TLS, il back-end riceve richieste HTTP e compila URI di reindirizzamento non corretti, a meno che non si configuri l'inoltro dell'intestazione.

Problema: il proxy termina HTTPS

Scenario:

  • L'utente si connette al proxy tramite HTTPS
  • Il proxy si connette al back-end tramite HTTP
  • Back-end compila URI di reindirizzamento HTTP (errato!)

Soluzione: intestazione X-Forwarded-Proto

Configurare il proxy per inviare l'intestazione X-Forwarded-Proto in modo che il back-end conosca lo schema originale.

Configurazione proxy (NGINX):

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

Configurare l'app per leggere l'intestazione proto inoltrata e impostare lo schema di richiesta:

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();

Errore comune: ciclo di reindirizzamento HTTPS

Problema:

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

Soluzione:

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

Configurare domini personalizzati

Usare un dominio personalizzato con Frontdoor di Azure per presentare un URL personalizzato agli utenti durante il routing del traffico ai servizi back-end.

Scenario: dominio personalizzato tramite Frontdoor di Azure

Architettura:

  • Dominio personalizzato: https://myapp.contoso.com
  • Frontdoor: https://myapp.azurefd.net (origine back-end)
  • Azure applicazione Web: https://myapp-backend.azurewebsites.net

Configurazione Front Door:

  1. Aggiungere un dominio myapp.contoso.com personalizzato a Frontdoor
  2. Configurare il certificato SSL (frontdoor gestito o personalizzato)
  3. Impostare il pool back-end su myapp-backend.azurewebsites.net
  4. Abilita solo HTTPS

Configurare l'app per accettare intestazioni inoltrate da Frontdoor:

// 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();
});

Registrare gli URI di callback sia di accesso che di disconnessione nella registrazione dell'app Microsoft Entra.

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

Usare l'endpoint di diagnostica seguente per verificare l'URI di reindirizzamento generato dall'app:

// 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}");
}

Registrare più URI di reindirizzamento

Quando l'app viene eseguita dietro gateway diversi in ambienti, registrare un URI di reindirizzamento per ognuno di essi.

Problema: stessa app, più gateway

Scenario:

  • Produzione: https://app.contoso.com (Frontdoor)
  • Staging: https://app-staging.azurewebsites.net (Diretto)
  • Sviluppo: https://localhost:5001 (locale)

Soluzione: Registrare tutti gli URI di reindirizzamento

Aggiungere ogni URI di reindirizzamento specifico dell'ambiente alla registrazione dell'applicazione Microsoft Entra.

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

Il codice dell'applicazione non richiede modifiche specifiche dell'ambiente:

var app = builder.Build();

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

Funzionamento:

  • L'applicazione compila dinamicamente l'URI di reindirizzamento in base alla richiesta in ingresso
  • HttpContext.Request.Scheme, Host e PathBase determinano l'URI
  • Purché sia registrato in Microsoft Entra ID, l'autenticazione ha esito positivo

Configurare il gateway applicativo Azure

Questa sezione fornisce un esempio di configurazione completo per la distribuzione di un'app Web dietro gateway applicazione di Azure con il routing basato sul percorso.

Esempio completo con il routing basato sul percorso

Impostazioni del gateway dell'applicazione:

Pool backend:

  • Destinazione: backend.azurewebsites.net o indirizzo IP

Impostazioni HTTP:

  • Protocollo: HTTPS (scelta consigliata) o HTTP
  • Porta: 443 o 80
  • Eseguire l'override del percorso back-end: No
  • Probe personalizzato: Sì

Probe di integrità:

  • Protocollo: HTTPS o HTTP
  • Host: lasciare il campo vuoto (utilizza il nome host del pool back-end)
  • Percorso: /health (deve essere un endpoint anonimo)
  • Intervallo: 30 secondi

Regola di routing:

  • Nome: webapp-rule
  • Listener: Listener HTTPS sulla porta 443
  • Pool back-end: Il tuo pool back-end
  • Impostazioni HTTP: le tue impostazioni HTTP

Configurare l'applicazione per gestire intestazioni inoltrate, autenticazione e probe di integrità:

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();

Aggiungere le impostazioni di autenticazione a appsettings.json:

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

Registrare gli URI di reindirizzamento rivolti al gateway nella registrazione dell'app Microsoft Entra:

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

Configurare Frontdoor di Azure

Questa sezione illustra come distribuire un'app Web in più aree dietro Frontdoor di Azure con l'autenticazione coerente.

Distribuzione di app Web in più aree

Scenario:

  • Frontdoor: https://app.azurefd.net (endpoint globale)
  • Stati Uniti orientali: https://app-eastus.azurewebsites.net
  • Stati Uniti occidentali: https://app-westus.azurewebsites.net
  • Utenti indirizzati all'area più vicina

Configurazione Front Door:

Gruppo di origini:

  • Nome: webapp-origins
  • Probe di integrità: /health
  • Bilanciamento del carico: basato sulla latenza

Origini:

  1. app-eastus.azurewebsites.net (priorità 1)
  2. app-westus.azurewebsites.net (priorità 1)

Percorso:

  • Percorso: /*
  • Protocollo di inoltro: solo HTTPS
  • Gruppo di origine: webapp-origins

Distribuire lo stesso codice dell'applicazione in entrambe le aree:

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();

Entrambe le regioni condividono la stessa registrazione dell'app Microsoft Entra con lo stesso URI di reindirizzamento:

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

Perché funziona:

  • L'URL di Frontdoor è coerente tra aree
  • Le intestazioni inoltrate garantiscono che le configurazioni back-end creino correttamente l'URI di reindirizzamento.
  • L'acquisizione di token avviene nel back-end a livello di area
  • La cache dei token distribuiti (Redis) condivide i token tra aree

Risolvere i problemi comuni

Questa sezione illustra gli errori di autenticazione più comuni nelle distribuzioni proxy e come risolverli.

Problema: errore "Mancata corrispondenza dell'URI di reindirizzamento"

Sintomi:

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'.

Possibili cause:

  1. Middleware per le intestazioni inoltrate mancanti

    // Fix: Add BEFORE authentication
    app.UseForwardedHeaders();
    app.UseAuthentication();
    
  2. URI di reindirizzamento errato registrato in Microsoft Entra ID

    • Controllare gli URI registrati nel portale di Azure
    • Assicurarsi di utilizzare HTTPS (non HTTP) in ambiente di produzione
    • Verificare che l'host corrisponda (inclusa la porta se non standard)
    • Verificare che il percorso includa PathBase, se applicabile
  3. Il proxy non inoltra le intestazioni

    • Controllare la configurazione del proxy
    • Verificare che X-Forwarded-Proto e X-Forwarded-Host siano impostati.
    • Test con curl: curl -H "X-Forwarded-Proto: https" -H "X-Forwarded-Host: gateway.com" http://backend:5000/
  4. PathBase non configurato

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

Aggiungi il seguente middleware di diagnostica per registrare l'URI di reindirizzamento creato dall'app:

// 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();
});

Problema: l'autenticazione funziona localmente ma non dietro il proxy

Sintomi:

  • L'accesso funziona su localhost:5001
  • L'accesso fallisce gateway.contoso.com
  • Errore: Mancata corrispondenza dell'URI di reindirizzamento o correlazione non riuscita

Elenco di controllo della soluzione:

  1. Intestazioni inoltrate configurate e usate come prioritarie
app.UseForwardedHeaders(); // Must be first!
  1. Proxy inoltra le intestazioni richieste
  • X-Forwarded-Proto: https
  • X-Forwarded-Host: gateway.contoso.com
  • Facoltativo: X-Forwarded-Prefix per il percorso base
  1. URI di reindirizzamento registrato in Microsoft Entra ID
  • https://gateway.contoso.com/signin-oidc
  1. PathBase configurato se necessario
app.UsePathBase("/myapp"); // If proxy adds prefix
  1. HTTPS applicato correttamente
app.UseForwardedHeaders(); // Reads X-Forwarded-Proto first
app.UseHttpsRedirection(); // Then enforces HTTPS

Problema: Sign-Out non riesce o reindirizza all'URL errato

Sintomi:

  • Accesso riuscito
  • Reindirizzamento durante la disconnessione a URL errato (localhost, http://, host errato)

Imposta il PostLogoutRedirectUri utilizzando il contesto della richiesta inoltrata:

// 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;
        };
    });

Registrare l'URI di callback per il sign-out nella registrazione dell'app di Microsoft Entra.

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

Problema: Ciclo di reindirizzamento infinito

Sintomi:

  • Il browser continua a reindirizzare tra app e Microsoft Entra ID
  • L'accesso non viene mai completato

Possibili cause:

  1. Reindirizzamento HTTPS prima delle intestazioni inoltrate

    // 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. Impostazioni dei cookie non compatibili con il proxy

    builder.Services.Configure<CookiePolicyOptions>(options =>
    {
        options.MinimumSameSitePolicy = SameSiteMode.None; // For cross-site scenarios
        options.Secure = CookieSecurePolicy.Always; // Requires HTTPS
    });
    
  3. Mancata corrispondenza del dominio cookie

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

Seguire le migliori pratiche

Applicare queste procedure a ogni distribuzione proxy per evitare problemi comuni.

1. Usare sempre il middleware per le intestazioni inoltrate

// 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. Registrare tutti gli URI di reindirizzamento

Registrare gli URI di reindirizzamento per ogni ambiente nella registrazione dell'app Microsoft Entra:

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

3. Testare la generazione dell'URI di reindirizzamento

Aggiungere un endpoint di diagnostica solo per lo sviluppo per verificare l'URI di reindirizzamento:

// 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. Endpoint di integrità per le sonde del gateway

Mappare l'endpoint di controllo dello stato di salute prima del middleware di autenticazione affinché i sondaggi del gateway non richiedano l'autenticazione.

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

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

5. Cache dei token distribuiti per più aree

Usare una cache distribuita come Redis per condividere i token tra aree:

// 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. Configurare la registrazione per la risoluzione dei problemi

Abilitare la registrazione di debug per Microsoft. Identity.Web e intestazioni inoltrate per diagnosticare i problemi:

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"
    }
  }
}

Esaminare un esempio completo

Questo esempio end-to-end distribuisce un'applicazione web tramite gateway applicazione di Azure con integrazione di Microsoft Graph.

Codice dell'applicazione

Di seguito Program.cs configura le intestazioni inoltrate, l'autenticazione con Microsoft Graph e i controlli di integrità:

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();

Aggiungere la configurazione di autenticazione e registrazione a 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"
    }
  }
}

Registrare gli URI seguenti nella registrazione dell'app Microsoft Entra:

URI di reindirizzamento:

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

URL di disconnessione del canale frontale:

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

Configurazione del Gateway Applicativo

Configurare le seguenti risorse del Gateway dell'applicazione:

Pool backend:

  • Nome: webapp-backend
  • Destinazione: webapp.azurewebsites.net o indirizzi IP

Impostazioni HTTP:

  • Nome: webapp-https-settings
  • Protocollo: HTTPS
  • Porta: 443
  • Eseguire l'override del percorso back-end: No
  • Scegliere il nome host dalla destinazione del backend: Sì
  • Probe personalizzato: Sì → webapp-health-probe

Probe di integrità:

  • Nome: webapp-health-probe
  • Protocollo: HTTPS
  • Selezionare il nome host dalle impostazioni HTTP back-end: Sì
  • Percorso: /health
  • Intervallo: 30 secondi
  • Soglia non salutare: 3

Listener:

  • Nome: webapp-listener
  • Frontend IP: pubblico
  • Protocollo: HTTPS
  • Porta: 443
  • Certificato SSL: il tuo certificato

Regola di routing:

  • Nome: webapp-rule
  • Tipo di regola: Basic
  • Listener: webapp-listener
  • Destinazione backend: webapp-backend
  • Impostazioni HTTP: webapp-https-settings