Ağ geçitlerinin arkasında korumalı API'leri kurma

Microsoft.Identity.Web ile korunan ASP.NET Core web API'lerini, Azure API Management (APIM), Azure Front Door ve Azure Application Gateway gibi Azure API ağ geçitleri ve ters proxy'lerin arkasında dağıtın.

Ağ geçidi gereksinimlerini anlama

Ağ geçitlerinin arkasında korumalı API'ler dağıttığınızda, çeşitli endişeleri işlemeniz gerekir:

  • İletilen üst bilgiler - Özgün istek bağlamını (düzen, konak, IP) koru
  • Belirteç doğrulama - hedef kitle taleplerinin ağ geçidi URL'leri ile eşleştiğinden emin olun
  • CORS yapılandırması - Çapraz kaynak isteklerini doğru işleme
  • Sağlık denetim uç noktaları - Doğrulanmamış sağlık denetimleri sağlama
  • Yol tabanlı yönlendirme - Ağ geçidi düzeyinde yol ön eklerini destekleme
  • SSL/TLS sonlandırma - Ağ geçidi SSL'i sonlandırdığında HTTPS'i düzgün bir şekilde işleme

Yaygın ağ geçidi senaryolarını gözden geçirme

Gereksinimlerinize göre bir ağ geçidi seçin. Aşağıdaki bölümlerde, korunan API'ler için en yaygın Azure ağ geçidi hizmetleri açıklanmaktadır.

Azure API Management (APIM)

Kullanım örneği: İlkeler, hız sınırlama, dönüştürme ile Kurumsal API ağ geçidi

Mimari:

Client → Microsoft Entra ID → Token
Client → APIM (apim.azure-api.net) → Backend API (app.azurewebsites.net)

Dikkat edilmesi gereken temel noktalar

  • APIM ilkeleri, arka uça iletmeden önce JWT belirteçlerini doğrulayabilir
  • Arka uç API'si belirteçleri doğrulamaya devam eder
  • hedef kitle talebi APIM URL'si veya arka uç URL'si ile eşleşmelidir (buna göre yapılandır)

Azure Front Door

Kullanım örneği: Genel yük dengeleme, CDN, DDoS koruması

Mimari:

Client → Microsoft Entra ID → Token
Client → Front Door (azurefd.net) → Backend API (regional endpoints)

Dikkat edilmesi gereken temel noktalar

  • Front Door, istekleri header'larla iletir X-Forwarded-*
  • Front Door'da SSL/TLS sonlandırma
  • Hedef kitle jeton doğrulaması yapılandırma gerektiriyor

Azure Application Gateway

Kullanım örneği: Bölgesel yük dengeleme, WAF, yol tabanlı yönlendirme

Mimari:

Client → Microsoft Entra ID → Token
Client → Application Gateway → Backend API (multiple instances)

Dikkat edilmesi gereken temel noktalar

  • Web Uygulaması Güvenlik Duvarı (WAF) tümleştirmesi
  • Yol tabanlı yönlendirme kuralları
  • Arka uç sistem durumu yoklamalarının kimliği doğrulanmamış uç noktalara ihtiyacı var

Ortak desenleri yapılandırma

Korumalı API'nizin herhangi bir ağ geçidinin arkasında düzgün çalıştığından emin olmak için bu yapılandırma desenlerini uygulayın.

1. İletilen üst bilgiler ara yazılımı

Bir ağ geçidinin arkasındayken her zaman iletilen üst bilgi ara yazılımını yapılandırın. Aşağıdaki kod ara yazılımı kaydeder ve kimlik doğrulamasından önce çalışacak şekilde ayarlar:

using Microsoft.AspNetCore.HttpOverrides;

var builder = WebApplication.CreateBuilder(args);

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

    // Clear known networks/proxies to accept forwarded headers from any source
    // (Azure infrastructure will be the proxy)
    options.KnownNetworks.Clear();
    options.KnownProxies.Clear();

    // Limit to specific headers if needed
    options.ForwardedForHeaderName = "X-Forwarded-For";
    options.ForwardedProtoHeaderName = "X-Forwarded-Proto";
    options.ForwardedHostHeaderName = "X-Forwarded-Host";
});

// Add authentication
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd"));

var app = builder.Build();

// USE forwarded headers BEFORE authentication middleware
app.UseForwardedHeaders();
app.UseAuthentication();
app.UseAuthorization();

app.Run();

İletilen üst bilgi ara yazılımı kritik bir öneme sahiptir çünkü:

  • Günlüğe kaydetmek için orijinal istemci IP adresini korur
  • HttpContext.Request.Scheme Özgün HTTPS düzeninin yansıtılmasını sağlar
  • Yeniden yönlendirme URL'leri ve belirteç doğrulaması için doğru Host üst bilgiyi sağlar

2. Belirteç hedef kitle yapılandırması

A Seçeneği: Hem ağ geçidi hem de arka uç URL'lerini kabul etme

Yapılandırmanıza appsettings.json birden çok geçerli hedef kitle ekleyin:

{
  "AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "TenantId": "your-tenant-id",
    "ClientId": "your-client-id",
    "Audience": "api://your-client-id",
    "TokenValidationParameters": {
      "ValidAudiences": [
        "api://your-client-id",
        "https://your-backend.azurewebsites.net",
        "https://your-apim.azure-api.net"
      ]
    }
  }
}

Alternatif olarak, Program.cs içinde program aracılığıyla birden çok hedef kitleyi yapılandırın.

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

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

// Customize token validation to accept multiple audiences
builder.Services.Configure<JwtBearerOptions>(JwtBearerDefaults.AuthenticationScheme, options =>
{
    var existingValidation = options.TokenValidationParameters.AudienceValidator;

    options.TokenValidationParameters.AudienceValidator = (audiences, token, parameters) =>
    {
        var validAudiences = new[]
        {
            "api://your-client-id",
            "https://your-backend.azurewebsites.net",
            "https://your-apim.azure-api.net",
            builder.Configuration["AzureAd:ClientId"] // Also accept ClientId
        };

        return audiences.Any(a => validAudiences.Contains(a, StringComparer.OrdinalIgnoreCase));
    };
});

B Seçeneği: APIM ilkesinde hedef kitleyi yeniden yazma

ApiM'yi arka uça iletmeden önce hedef kitle iddiasını doğrulayacak şekilde yapılandırın:

<policies>
    <inbound>
        <validate-jwt header-name="Authorization" failed-validation-httpcode="401">
            <openid-config url="https://login.microsoftonline.com/{tenant-id}/v2.0/.well-known/openid-configuration" />
            <audiences>
                <audience>api://your-client-id</audience>
            </audiences>
        </validate-jwt>

        <!-- Optionally modify token claims for backend -->
        <set-header name="X-Gateway-Validated" exists-action="override">
            <value>true</value>
        </set-header>
    </inbound>
</policies>

3. Sağlık durumu uç noktası yapılandırması

Ağ geçitleri, yoklamalar için kimliği doğrulanmamış sistem durumu uç noktaları gerektirir. Belirteç doğrulamasını atlamak için kimlik doğrulama ara yazılımından önce bir sağlık durumu uç noktasını yönlendirin.

var app = builder.Build();

// Health endpoint BEFORE authentication middleware
app.MapGet("/health", () => Results.Ok(new { status = "healthy" }))
    .AllowAnonymous();

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

// Protected endpoints require authentication
app.MapControllers();

app.Run();

Alternatif olarak, daha zengin sistem durumu raporlaması için yerleşik ASP.NET Core Sistem Durumu Denetimleri çerçevesini kullanın:

using Microsoft.Extensions.Diagnostics.HealthChecks;

builder.Services.AddHealthChecks()
    .AddCheck("api", () => HealthCheckResult.Healthy());

var app = builder.Build();

app.MapHealthChecks("/health").AllowAnonymous();
app.MapHealthChecks("/ready").AllowAnonymous();

app.UseForwardedHeaders();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();

app.Run();

4. Ağ geçitlerinin arkasındaki CORS yapılandırması

ön uç uygulamalarıyla Azure Front Door veya APIM kullandığınızda CORS'yi ağ geçidi kaynaklarınızdan gelen isteklere izin verecek şekilde yapılandırın:

builder.Services.AddCors(options =>
{
    options.AddPolicy("AllowGateway", policy =>
    {
        policy.WithOrigins(
            "https://your-apim.azure-api.net",
            "https://your-frontend.azurefd.net",
            "https://your-app.azurewebsites.net"
        )
        .AllowAnyMethod()
        .AllowAnyHeader()
        .AllowCredentials(); // If using cookies
    });
});

var app = builder.Build();

app.UseForwardedHeaders();
app.UseCors("AllowGateway");
app.UseAuthentication();
app.UseAuthorization();

app.Run();

Önemli

CORS, iletilen üst bilgilerden sonra ve kimlik doğrulaması öncesinde yapılandırılmalıdır.


Azure API Management ile tümleştirme

Bu bölüm, Azure API Management arkasında korumalı bir API dağıtmak için tam yapılandırma sağlar.

Arka uç API'sini yapılandırma

Program.cs'da yönlendirilmiş başlıkları ve Microsoft Entra ID kimlik doğrulamasını ayarlayın:

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

var builder = WebApplication.CreateBuilder(args);

// Forwarded headers for APIM
builder.Services.Configure<ForwardedHeadersOptions>(options =>
{
    options.ForwardedHeaders = ForwardedHeaders.All;
    options.KnownNetworks.Clear();
    options.KnownProxies.Clear();
});

// Authentication
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd"));

builder.Services.AddControllers();

var app = builder.Build();

// Middleware order matters
app.UseForwardedHeaders();
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();

app.Run();

Microsoft Entra yapılandırmasını appsettings.json ekleyin:

{
  "AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "TenantId": "your-tenant-id",
    "ClientId": "your-backend-api-client-id",
    "Audience": "api://your-backend-api-client-id"
  }
}

JWT doğrulaması için APIM gelen ilkesi ekleyin

JWT belirtecini doğrulayan, hız sınırlama uygulayan ve isteği arka uça ileden bir gelen ilkesi tanımlayın:

<policies>
    <inbound>
        <base />

        <!-- Validate JWT token -->
        <validate-jwt header-name="Authorization" failed-validation-httpcode="401" failed-validation-error-message="Unauthorized">
            <openid-config url="https://login.microsoftonline.com/{your-tenant-id}/v2.0/.well-known/openid-configuration" />
            <audiences>
                <audience>api://your-backend-api-client-id</audience>
            </audiences>
            <issuers>
                <issuer>https://login.microsoftonline.com/{your-tenant-id}/v2.0</issuer>
            </issuers>
            <required-claims>
                <claim name="scp" match="any">
                    <value>access_as_user</value>
                </claim>
            </required-claims>
        </validate-jwt>

        <!-- Rate limiting -->
        <rate-limit calls="100" renewal-period="60" />

        <!-- Forward original host header -->
        <set-header name="X-Forwarded-Host" exists-action="override">
            <value>@(context.Request.OriginalUrl.Host)</value>
        </set-header>

        <!-- Forward to backend -->
        <set-backend-service base-url="https://your-backend.azurewebsites.net" />
    </inbound>

    <backend>
        <base />
    </backend>

    <outbound>
        <base />
    </outbound>

    <on-error>
        <base />
    </on-error>
</policies>

APIM API ayarlarını yapılandırma

APIM yapılandırmasını tamamlamak için aşağıdaki adlandırılmış değerleri ve API ayarlarını kullanın:

Adlandırılmış Değerler (yeniden kullanılabilirlik için):

  • tenant-id: Microsoft Entra kiracı kimliğiniz
  • backend-api-client-id: Arka uç API'lerinin istemci kimliği
  • backend-base-url: https://your-backend.azurewebsites.net

API Ayarları:

  • API URL'si son eki: /api (isteğe bağlı yol ön eki)
  • Web hizmeti URL'si: Adlandırılmış değerler kullanılarak ilke aracılığıyla ayarlanır
  • Abonelik gerekli: Evet (başka bir güvenlik katmanı ekler)

İstemci uygulamasını yapılandırma

İstemci uygulamaları, APIM için değil arka uç API'sine yönelik belirteçler istemektedir. Aşağıdaki kod bir belirteç alır ve APIM uç noktası üzerinden API'yi çağırır:

// Client app requests token
var result = await app.AcquireTokenSilent(
    scopes: new[] { "api://your-backend-api-client-id/access_as_user" },
    account)
    .ExecuteAsync();

// Call APIM URL with token
var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
    new AuthenticationHeaderValue("Bearer", result.AccessToken);

// Add APIM subscription key
client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", "your-subscription-key");

var response = await client.GetAsync("https://your-apim.azure-api.net/api/weatherforecast");

Azure Front Door ile tümleştirme

Korumalı API'nizi Azure Front Door arkasındaki genel dağıtım için yapılandırın.

Arka uç API'sini yapılandırma

Program.cs'da Azure Front Door için iletilen üst bilgileri ayarlama:

using Microsoft.AspNetCore.HttpOverrides;

var builder = WebApplication.CreateBuilder(args);

// Configure for Azure Front Door
builder.Services.Configure<ForwardedHeadersOptions>(options =>
{
    options.ForwardedHeaders = ForwardedHeaders.XForwardedFor |
                                ForwardedHeaders.XForwardedProto |
                                ForwardedHeaders.XForwardedHost;

    // Accept headers from any source (Azure Front Door)
    options.KnownNetworks.Clear();
    options.KnownProxies.Clear();

    // Front Door specific headers
    options.ForwardedForHeaderName = "X-Forwarded-For";
    options.ForwardedProtoHeaderName = "X-Forwarded-Proto";
});

builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd"));

var app = builder.Build();

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

app.MapControllers();

app.Run();

Front Door kaynaklarını yapılandırma

Front Door kaynağını ayarlamak için Azure portalında aşağıdaki adımları tamamlayın:

  1. Front Door profili oluşturma
  2. Arka uç API örneklerinizle kaynak grubu ekleme
  3. Sağlık yoklamalarını /health uç noktasına yapılandırın
  4. Yalnızca HTTPS iletmeyi ayarlama
  5. WAF ilkesini etkinleştirme (isteğe bağlı)

Sağlık Yoklaması Ayarları:

  • Yol: /health
  • Protokol: HTTPS
  • Yöntem: GET
  • Aralık: 30 saniye

Birden çok bölgeyi işleme

Front Door üzerinden birden çok bölgeye dağıtırken, günlük kaydı ve tanılama için bölge tanımlaması ekleyin.

// Add region awareness for logging/diagnostics
builder.Services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();

app.Use(async (context, next) =>
{
    // Log the actual client IP and region
    var clientIp = context.Connection.RemoteIpAddress?.ToString();
    var forwardedFor = context.Request.Headers["X-Forwarded-For"].ToString();
    var frontDoorId = context.Request.Headers["X-Azure-FDID"].ToString();

    // Add to logger scope or response headers
    context.Response.Headers.Add("X-Served-By-Region",
        builder.Configuration["Region"] ?? "unknown");

    await next();
});

Front Door ile belirteçleri doğrulama

İstemciler Front Door URL'si kapsamında belirteçler isterse, bunu geçerli hedef kitleler listesine ekleyin:

builder.Services.Configure<JwtBearerOptions>(JwtBearerDefaults.AuthenticationScheme, options =>
{
    options.TokenValidationParameters.ValidAudiences = new[]
    {
        "api://your-backend-api-client-id",
        "https://your-frontend.azurefd.net", // Front Door URL
        builder.Configuration["AzureAd:ClientId"]
    };
});

Azure Application Gateway ile tümleştirme

korumalı API'nizi Web Uygulaması Güvenlik Duvarı (WAF) desteğiyle Azure Application Gateway arkasında yapılandırın.

Arka uç API'sini yapılandırma

içinde Application Gateway Program.csiçin iletilen üst bilgileri ayarlayın:

using Microsoft.AspNetCore.HttpOverrides;

var builder = WebApplication.CreateBuilder(args);

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

builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd"));

builder.Services.AddHealthChecks();

var app = builder.Build();

// Health endpoint for Application Gateway probes
app.MapHealthChecks("/health").AllowAnonymous();

app.UseForwardedHeaders();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();

app.Run();

Application Gateway ayarlarını yapılandırma

Azure portalında aşağıdaki arka uç, sistem durumu yoklaması ve WAF ayarlarını yapın:

Arka Uç Ayarları:

  • Protokol: HTTPS (önerilen) veya HTTP
  • Bağlantı noktası: 443 veya 80
  • Arka uç yolunu geçersiz kıl: Hayır (gerekmedikçe)
  • Özel prob: Evet, işaret eden /health

Sistem Durumu Yoklaması:

  • Protokol: HTTPS veya HTTP
  • Sunucu: Varsayılanı bırakın veya belirtin
  • Yol: /health
  • Aralık: 30 saniye
  • Sağlıksız eşik: 3

WAF İlkesi:

  • OWASP 3.2 kural kümesiyle WAF'yi etkinleştirme
  • Önemli: Üst bilgilerdeki Authorization JWT belirteçlerinin engellenmediğinden emin olun
  • "RequestHeaderNames içinde 'Yetkilendirme' bulunan WAF dışlamaları oluşturmanız gerekebilir."

Yol tabanlı yönlendirmeyi ayarlama

Yol tabanlı yönlendirme kurallarını kullandığınızda arka uç API'nizi yol ön ekini işleyecek şekilde yapılandırın:

// Backend API should work regardless of path prefix
var app = builder.Build();

// Option 1: Use path base (if gateway adds prefix)
app.UsePathBase("/api/v1");

// Option 2: Configure routing explicitly
app.UseForwardedHeaders();
app.UseAuthentication();
app.UseAuthorization();

app.MapControllers();

app.Run();

Application Gateway Kuralı:

  • Yol: /api/v1/*
  • Arka uç hedefi: Arka uç havuzunuz
  • Arka uç ayarları: Yapılandırılmış ayarları kullanma

Yaygın sorunları giderme

Ağ geçitlerinin arkasında korumalı API'leri dağıtırken karşılaşılan en yaygın sorunları çözmek için bu çözümleri kullanın.

Sorun: 401 Ağ geçidi arkasında dağıtımdan sonra yetkisiz

Belirtiler:

  • API yerel olarak çalışır ancak ağ geçidi üzerinden 401 döndürür
  • Jeton jwt.ms'de çözüldüğünde geçerli görünüyor.

Olası nedenler:

  1. Hedef kitle beyanı uyuşmazlığı

    # Check token audience
    # Decode token and verify 'aud' claim matches one of:
    # - api://your-client-id
    # - https://your-backend.azurewebsites.net
    # - https://your-gateway-url
    
  2. Eksik iletilen üst bilgiler ara yazılımı

    // Ensure this is BEFORE authentication
    app.UseForwardedHeaders();
    app.UseAuthentication();
    
  3. HTTPS yeniden yönlendirme sorunları

    // If gateway terminates SSL, may need to disable or configure carefully
    if (!app.Environment.IsDevelopment())
    {
        app.UseHttpsRedirection();
    }
    

Çözüm:

  • Belirteç doğrulama ayrıntılarını görmek için hata ayıklama günlüğünü etkinleştirme
  • Belirteç doğrulamasına birden çok geçerli hedef kitle ekleme
  • X-Forwarded-* başlıkların ağ geçidi tarafından iletildiğini doğrulayın

Problem: Sağlık kontrolleri başarısız

Belirtiler:

  • Ağ geçidi arka ucu iyi durumda değil olarak işaretler
  • Sağlık uç noktası 401 döndürür

Çözüm:

Kimlik doğrulama orta katman yazılımından önce sağlık kontrolü uç noktasının çalıştığından emin olun.

// Ensure health endpoint is BEFORE authentication
app.MapHealthChecks("/health").AllowAnonymous();

// Alternative: Use custom middleware
app.Map("/health", healthApp =>
{
    healthApp.Run(async context =>
    {
        context.Response.StatusCode = 200;
        await context.Response.WriteAsync("healthy");
    });
});

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

Sorun: Front Door'un arkasındaki CORS hataları

Belirtiler:

  • "Ön Kontrol seçenek istekleri başarısız oldu"
  • Tarayıcı konsolu CORS hatalarını gösteriyor

Çözüm:

Front Door ve ön uç kaynaklarınızı CORS ilkesine ekleyin:

builder.Services.AddCors(options =>
{
    options.AddDefaultPolicy(policy =>
    {
        policy.WithOrigins(
            "https://your-frontend.azurefd.net",
            "https://your-app.com"
        )
        .AllowAnyMethod()
        .AllowAnyHeader()
        .AllowCredentials();
    });
});

var app = builder.Build();

app.UseForwardedHeaders();
app.UseCors(); // Before authentication
app.UseAuthentication();
app.UseAuthorization();

Sorun: Günlüklerde "İletilen başlık" uyarıları

Belirtiler:

Microsoft.AspNetCore.HttpOverrides.ForwardedHeadersMiddleware: Unknown proxy

Çözüm:

Azure altyapısından iletilen üst bilgileri kabul etmek için bilinen ağları ve proxy'leri temizleyin:

builder.Services.Configure<ForwardedHeadersOptions>(options =>
{
    // Clear known networks to accept from any proxy
    options.KnownNetworks.Clear();
    options.KnownProxies.Clear();

    // Or explicitly add Azure IP ranges (more secure but complex)
    // options.KnownProxies.Add(IPAddress.Parse("20.x.x.x"));
});

Sorun: APIM 401 döndürürken arka uç 200 döndürür

Belirtiler:

  • Token arka uç için geçerlidir
  • APIM validate-jwt ilkesi başarısız oluyor

Çözüm:

APIM ilkesinin kitlesinin jeton kitlesiyle eşleştiğini doğrulayın.

<validate-jwt header-name="Authorization">
    <openid-config url="https://login.microsoftonline.com/{tenant}/v2.0/.well-known/openid-configuration" />
    <audiences>
        <!-- Must match the 'aud' claim in your token -->
        <audience>api://your-backend-api-client-id</audience>
    </audiences>
</validate-jwt>

Sorun: Birden çok kimlik doğrulama düzeni çakışıyor

Belirtiler:

  • Hem JWT taşıyıcısı hem de diğer şemaları kullanma
  • Yanlış düzen seçildi

Çözüm:

Kimlik doğrulama düzenini denetleyicide açıkça belirtin:

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

builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd"))
    .AddScheme<MyCustomOptions, MyCustomHandler>("CustomScheme", options => {});

// In controller, specify scheme explicitly
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
public class WeatherForecastController : ControllerBase
{
    // ...
}

En iyi yöntemleri izleyin

Ağ geçitlerinin arkasında güvenli, dayanıklı bir API dağıtımı oluşturmak için bu uygulamaları uygulayın.

1. Derinlemesine savunma

Ağ geçidi tarafından doğrulansa bile arka uç API'sindeki belirteçleri her zaman doğrulayın:

// Gateway validates token (APIM policy)
// Backend ALSO validates token (Microsoft.Identity.Web)
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd"));

Ağ geçidi yapılandırması değişebilir ve belirteçler yeniden yürütülebilir. Derinlemesine savunma, güvenlik için kritik öneme sahiptir.

2. Ağ geçidi-arka uç iletişimi için yönetilen kimlikleri kullanma

Ağ geçidiniz kendi kimliğiyle arka uça çağrıda bulunuyorsa, arka ucu hem kullanıcı belirteçlerini hem de yönetilen kimlik belirteçlerini kabul edecek şekilde yapılandırın.

// Backend accepts both user tokens and gateway's managed identity
builder.Services.Configure<JwtBearerOptions>(JwtBearerDefaults.AuthenticationScheme, options =>
{
    options.TokenValidationParameters.ValidAudiences = new[]
    {
        "api://backend-api-client-id", // User tokens
        "https://management.azure.com" // Managed identity tokens (if applicable)
    };
});

3. Ağ geçidi ölçümlerini izleme

Ağ geçidi dağıtımınızda görünürlüğü korumak için şu önemli ölçümleri izleyin:

  • 401/403 hata oranları
  • Belirteç doğrulama hataları
  • Sağlık sondası hataları
  • İletilen üstbilgiler (hata ayıklama için)

4. Application Insights kullanma

Gateway'e özgü istek özelliklerini günlüğe kaydetmek amacıyla Application Insights telemetrisini ekleyin.

builder.Services.AddApplicationInsightsTelemetry();

// Log custom properties
app.Use(async (context, next) =>
{
    var telemetry = context.RequestServices.GetRequiredService<TelemetryClient>();
    telemetry.TrackEvent("ApiRequest", new Dictionary<string, string>
    {
        ["ForwardedFor"] = context.Request.Headers["X-Forwarded-For"],
        ["OriginalHost"] = context.Request.Headers["X-Forwarded-Host"],
        ["Gateway"] = "APIM" // or "FrontDoor", "AppGateway"
    });

    await next();
});

5. Sağlığı hazırdan ayırın

Canlılık (hizmet çalışıyor mu?) ve hazır olma (hizmet trafiği kabul edebilir mi?) denetimleri için ayrı uç noktaları kullanın:

// Health: Is the service running?
app.MapGet("/health", () => Results.Ok()).AllowAnonymous();

// Ready: Can the service accept traffic?
app.MapHealthChecks("/ready", new HealthCheckOptions
{
    Predicate = check => check.Tags.Contains("ready")
}).AllowAnonymous();

builder.Services.AddHealthChecks()
    .AddCheck("database", () => /* check DB */ , tags: new[] { "ready" })
    .AddCheck("cache", () => /* check cache */ , tags: new[] { "ready" });

6. Ağ geçidi yapılandırmanızı belgeleyin

README veya wiki sayfası belgeler oluşturun:

  • Hangi ağ geçitleri kullanımda
  • Belirteç hedef kitlesi beklentileri
  • CORS yapılandırması
  • Sağlık denetimi uç noktaları
  • İletilen başlık yapılandırması
  • Acil durum geri alma prosedürleri

Azure API Management ile eksiksiz bir örnek oluşturma

Bu bölümde, Microsoft Entra ID kimlik doğrulamasıyla Azure API Management arkasında ASP.NET Core API'sinin üretime hazır tam bir örneği sağlanır.

Arka uç API'si (ASP.NET Core)

Aşağıdaki Program.cs iletilen üst bilgileri, Microsoft Entra kimlik doğrulamasını, sistem durumu denetimlerini ve Application Insights'ı yapılandırıyor:

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

var builder = WebApplication.CreateBuilder(args);

// Forwarded headers for APIM
builder.Services.Configure<ForwardedHeadersOptions>(options =>
{
    options.ForwardedHeaders = ForwardedHeaders.All;
    options.KnownNetworks.Clear();
    options.KnownProxies.Clear();
});

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

// Application Insights
builder.Services.AddApplicationInsightsTelemetry();

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

builder.Services.AddControllers();

var app = builder.Build();

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

// Middleware order is critical
app.UseForwardedHeaders();
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseAuthorization();

app.MapControllers();

app.Run();

Aşağıdaki Microsoft Entra ve Application Insights yapılandırmasını appsettings.json'a ekleyin:

{
  "AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "TenantId": "your-tenant-id",
    "ClientId": "backend-api-client-id",
    "Audience": "api://backend-api-client-id"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning",
      "Microsoft.Identity.Web": "Debug"
    }
  },
  "ApplicationInsights": {
    "ConnectionString": "your-connection-string"
  }
}

Aşağıdaki denetleyici, kimlik doğrulaması gerektirir ve hata ayıklama için iletilen üst bilgileri günlüğe kaydeder:

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

[Authorize]
[ApiController]
[Route("[controller]")]
[RequiredScope("access_as_user")]
public class WeatherForecastController : ControllerBase
{
    private readonly ILogger<WeatherForecastController> _logger;

    public WeatherForecastController(ILogger<WeatherForecastController> logger)
    {
        _logger = logger;
    }

    [HttpGet]
    public IActionResult Get()
    {
        // Log forwarded headers for debugging
        var forwardedFor = HttpContext.Request.Headers["X-Forwarded-For"];
        var forwardedHost = HttpContext.Request.Headers["X-Forwarded-Host"];

        _logger.LogInformation(
            "Request from {ForwardedFor} via {ForwardedHost}",
            forwardedFor,
            forwardedHost);

        return Ok(new[] { "Weather", "Forecast", "Data" });
    }
}

APIM yapılandırması

Aşağıdaki gelen ilke JWT belirteçlerini doğrular, hız sınırlama uygular, üst bilgileri iletir ve CORS'yi yapılandırir:

<policies>
    <inbound>
        <base />

        <!-- Rate limiting per subscription -->
        <rate-limit-by-key calls="100" renewal-period="60"
                           counter-key="@(context.Subscription.Id)" />

        <!-- Validate JWT -->
        <validate-jwt header-name="Authorization"
                      failed-validation-httpcode="401"
                      failed-validation-error-message="Unauthorized">
            <openid-config url="https://login.microsoftonline.com/{tenant-id}/v2.0/.well-known/openid-configuration" />
            <audiences>
                <audience>api://backend-api-client-id</audience>
            </audiences>
            <issuers>
                <issuer>https://login.microsoftonline.com/{tenant-id}/v2.0</issuer>
            </issuers>
            <required-claims>
                <claim name="scp" match="any">
                    <value>access_as_user</value>
                </claim>
            </required-claims>
        </validate-jwt>

        <!-- Forward headers -->
        <set-header name="X-Forwarded-Host" exists-action="override">
            <value>@(context.Request.OriginalUrl.Host)</value>
        </set-header>
        <set-header name="X-Forwarded-Proto" exists-action="override">
            <value>@(context.Request.OriginalUrl.Scheme)</value>
        </set-header>

        <!-- Backend URL -->
        <set-backend-service base-url="https://your-backend.azurewebsites.net" />
    </inbound>

    <backend>
        <base />
    </backend>

    <outbound>
        <base />

        <!-- Add CORS headers if needed -->
        <cors>
            <allowed-origins>
                <origin>https://your-frontend.com</origin>
            </allowed-origins>
            <allowed-methods>
                <method>GET</method>
                <method>POST</method>
            </allowed-methods>
            <allowed-headers>
                <header>*</header>
            </allowed-headers>
        </cors>
    </outbound>

    <on-error>
        <base />
    </on-error>
</policies>