.NET Aspire uygulamasına Microsoft Entra ID kimlik doğrulaması ekleme

Bu kılavuzda Microsoft Entra ID kimlik doğrulaması ve yetkilendirme ile .NET Aspire dağıtılmış uygulamanın güvenliğini sağlama gösterilmektedir. Aşağıdakileri kapsar:

  1. Blazor Server ön yüz (MyService.Web): OpenID Connect ile kullanıcı oturumu açma ve jeton alma
  2. Korumalı API arka uç (MyService.ApiService): Microsoft.Identity.Web kullanarak JWT doğrulaması.
  3. Uçtan uca akış: Blazor erişim belirteçlerini alır ve Aspire servis keşfi ile korumalı API'yi çağırır

Bu kılavuzda, aşağıdaki komutu kullanarak oluşturulan bir Aspire projesiyle başladığınız varsayılır:

aspire new aspire-starter --name MyService

Önkoşullar

  • .NET 9 SDK veya üzeri
  • .NET Aspire CLI - Bkz. Aspire CLI'yı yükleme
  • Microsoft Entra tenant — Kurulum için bkz. Microsoft Entra ID

Tip

Aspire'de yeni misiniz? Bkz. .NET Aspire genel bakış.

İki aşamalı iş akışını anlama

Bu kılavuzda iki aşamalı bir yaklaşım izlenir:

Phase Ne olur? Result
1. Aşama Yer tutucu değerleriyle kimlik doğrulama kodu ekleme Uygulama derleniyor ama çalışmıyor
2. Aşama Microsoft Entra uygulama kayıtlarını sağlama Uygulama gerçek kimlik doğrulaması ile çalışır

uygulamaları Microsoft Entra ID'a kaydetme

Uygulamanızın kullanıcıların kimliğini doğrulayabilmesi için önce Microsoft Entra iki uygulama kaydına ihtiyacınız vardır:

Uygulama Kaydı Amaç Anahtar yapılandırması
API (MyService.ApiService) Gelen belirteçleri doğrular Uygulama Kimliği URI'si, access_as_user kapsam
Web Uygulaması (MyService.Web) Kullanıcılar oturum açar, tokenları alır Yeniden yönlendirme URI'leri, istemci sırrı, API izinleri

Zaten yapılandırılmış uygulama kayıtlarınız varsa, için appsettings.jsonbu değerlere ihtiyacınız vardır:

  • TenantId — Microsoft Entra kiracı kimliğiniz
  • API ClientId — API uygulama kaydınızın uygulama (istemci) kimliği
  • API Uygulama Kimliği URI'si — Genellikle api://<api-client-id> (ve Audiencesiçinde Scopes kullanılır)
  • Web App ClientId — Web uygulaması kaydınızın uygulama (istemci) kimliği
  • İstemci Gizli Anahtarı (veya sertifikası) — Web uygulamasının kimlik bilgileri (appsettings.jsondeğil, kullanıcı gizli dizilerinde depolayın)
  • Kapsamlar — Web uygulamanızın istediği kapsamlar, örneğin api://<api-client-id>/.default veya api://<api-client-id>/access_as_user

1. Adım: API'yi kaydetme

  1. Microsoft Entra yönetim merkezi>Identity>Applications>Uygulama kayıtları'a gidin.
  2. Yeni kayıtseçin.
    • Ad:MyService.ApiService
    • Desteklenen hesap türleri: Yalnızca bu kuruluş dizinindeki hesaplar (Tek kiracı)
    • Kaydıseçin.
  3. Uygulama Kimliği URI'si'nin yanındaki API'yi Kullanıma Aç>Ekle'ye gidin.
    • Varsayılanı (api://<client-id>) kabul edin veya özelleştirin.
    • Kapsam ekle'yi seçin:
      • Kapsam adı:access_as_user
      • Kim onay verebilir: Yöneticiler ve kullanıcılar
      • Yönetici onayı görünen adı: MyService API'lerine erişim
      • Yönetici onayı açıklaması: Uygulamanın oturum açmış kullanıcı adına MyService API'sine erişmesine izin verir.
      • Kapsam ekle'yi seçin.
  4. Uygulama (istemci) kimliğini kopyalayın; her iki dosya için de appsettings.json buna ihtiyacınız olacaktır.

Daha fazla bilgi için bkz . Hızlı Başlangıç: Web API'sini kullanıma açmak için uygulama yapılandırma.

2. Adım: Web uygulamasını kaydetme

  1. Uygulama kayıtları>Yeni kayıt gidin.
    • Ad:MyService.Web
    • Desteklenen hesap türleri: Yalnızca bu kuruluş dizinindeki hesaplar
    • Yeniden yönlendirme URI'si:Web seçeneğini seçin ve uygulamanızın URL'si + /signin-oidc
      • Yerel geliştirme için: https://localhost:7001/signin-oidc (gerçek bağlantı noktasını denetleyin launchSettings.json )
    • Kaydıseçin.
  2. Tüm geliştirme URL'lerinizi eklemek için Kimlik Doğrulama>URI Ekle bölümüne (kaynak: launchSettings.json) gidin.
  3. Sertifikalar ve sırlar>İstemci sırları>Yeni istemci sırrı bölümüne gidin.
    • Açıklama ve süre sonu ekleyin.
    • Gizli değeri hemen kopyalayın, bir daha gösterilmeyecek.
  4. API izinleri> İzinekle>API'lerim'e gidin.
    • MyService.ApiServiceseçin.
    • access_as_user seçin>.
    • [kiracı] için yönetici onayı ver'i seçin (veya kullanıcılardan ilk kullanımda istenir).
  5. Web uygulamasının appsettings.json kopyalayın.

Uyarı

Bazı kuruluşlar istemci sırlarına izin vermez. Alternatifler için bkz. Sertifika kimlik bilgileri veya Sertifikasız kimlik doğrulaması.

Daha fazla bilgi için bkz . Hızlı Başlangıç: Uygulama kaydetme.

3. Adım: Yapılandırmayı güncelleştirme

Uygulama kayıtlarını oluşturduktan sonra dosyalarınızı güncelleştirin appsettings.json :

API (MyService.ApiService/appsettings.json):

{
  "AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "TenantId": "YOUR_TENANT_ID",
    "ClientId": "YOUR_API_CLIENT_ID",
    "Audiences": ["api://YOUR_API_CLIENT_ID"]
  }
}

Web Uygulaması (MyService.Web/appsettings.json):

{
  "AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "TenantId": "YOUR_TENANT_ID",
    "ClientId": "YOUR_WEB_CLIENT_ID",
    "CallbackPath": "/signin-oidc",
    "ClientCredentials": [
      { "SourceType": "ClientSecret" }
    ]
  },
  "WeatherApi": {
    "Scopes": ["api://YOUR_API_CLIENT_ID/.default"]
  }
}

Gizli bilgiyi güvenli bir şekilde saklayın:

cd MyService.Web
dotnet user-secrets set "AzureAd:ClientCredentials:0:ClientSecret" "YOUR_SECRET_VALUE"
Değer Nerede bulunur?
TenantId Microsoft Entra yönetim merkezi > Genel Bakış > Kiracı Kimliği
API ClientId Uygulama kayıtları > MyService.ApiService > Uygulama (istemci) Kimliği
Web ClientId Uygulama Kayıtları > MyService.Web > Uygulama (istemci) kimliği
Client Secret 2. Adımda Oluşturuldu (oluşturulduğunda hemen kopyalayın)

Uyarı

Aspire starter şablonu, WeatherApiClient projesinde otomatik olarak bir MyService.Web sınıf oluşturur. Bu türdeki HttpClient, korumalı API'yi çağırmayı göstermek için bu kılavuz boyunca kullanılır. Bu sınıfı kendiniz oluşturmanız gerekmez; şablonun bir parçasıdır.


Hızlı bir başlangıç yapın

Bu bölümde, kimlik doğrulaması eklemek için özlü bir kaynak sağlanır. Ayrıntılı kılavuzlar için bkz Bölüm 1 ve Bölüm 2.

API (MyService.ApiService)

Microsoft.Identity.Web NuGet paketini yükleyin.

dotnet add package Microsoft.Identity.Web

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

{
  "AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "TenantId": "<tenant-id>",
    "ClientId": "<api-client-id>",
    "Audiences": ["api://<api-client-id>"]
  }
}

kimlik doğrulama ve yetkilendirmeyi içinde Program.cskaydedin:

builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd"));
builder.Services.AddAuthorization();
// ...
app.UseAuthentication();
app.UseAuthorization();
// ...
app.MapGet("/weatherforecast", () => { /* ... */ }).RequireAuthorization();

Web Uygulaması (MyService.Web)

Microsoft.Identity.Web NuGet paketini yükleyin.

dotnet add package Microsoft.Identity.Web

Microsoft Entra yapılandırmasını appsettings.json üzerine ekleyin.

{
  "AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "TenantId": "<tenant-id>",
    "ClientId": "<web-client-id>",
    "CallbackPath": "/signin-oidc",
    "ClientCredentials": [{ "SourceType": "ClientSecret" }]
  },
  "WeatherApi": { "Scopes": ["api://<api-client-id>/.default"] }
}

kimlik doğrulama, belirteç alımı ve aşağı akış API istemcisi yapılandırmasını Program.cs içinde yapın:

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

builder.Services.AddCascadingAuthenticationState();
builder.Services.AddScoped<BlazorAuthenticationChallengeHandler>();

builder.Services.AddHttpClient<WeatherApiClient>(client =>
    client.BaseAddress = new("https+http://apiservice"))
    .AddMicrosoftIdentityMessageHandler(builder.Configuration.GetSection("WeatherApi"));
// ...
app.UseAuthentication();
app.UseAuthorization();
app.MapGroup("/authentication").MapLoginAndLogout();

MicrosoftIdentityMessageHandler belirteçleri otomatik olarak edinir ve ekler, BlazorAuthenticationChallengeHandler ise onay ve Koşullu Erişim zorluklarını işler.

Önemli

Oturum açma düğmesi için UserInfo.razor oluşturmayı unutmayın. Ayrıntılar için bkz . Blazor kullanıcı arabirimi bileşenleri ekleme .

Uyarı

BlazorAuthenticationChallengeHandler ve LoginLogoutEndpointRouteBuilderExtensions, Microsoft.Identity.Web (v3.3.0+) ile birlikte teslim edilir. Dosya kopyalama gerekmez.


Değiştireceğiniz dosyaları tanımlama

Aşağıdaki tabloda, her projede değiştirdiğiniz dosyalar listelenir:

Proje Dosya Değişiklikler
ApiService Program.cs JWT Taşıyıcı kimlik doğrulaması, yetkilendirme ara yazılımı
appsettings.json Microsoft Entra yapılandırması
.csproj Microsoft.Identity.Web ekleme
Web Program.cs OIDC kimlik doğrulama, belirteç edinme, BlazorAuthenticationChallengeHandler
appsettings.json Microsoft Entra yapılandırması, alt akış API kapsamları
.csproj Microsoft.Identity.Web ekleyin (v3.3.0+)
Components/UserInfo.razor Oturum açma düğmesi kullanıcı arabirimi (yeni dosya)
Components/Layout/MainLayout.razor UserInfo bileşenini dahil et
Components/Routes.razor Korumalı sayfalar için AuthorizeRouteView
API'leri çağıran sayfalar ChallengeHandler ile deneyin/yakalayın

Kimlik doğrulama akışını anlama

Aşağıdaki diyagramda Blazor ön ucu, Microsoft Entra ve korumalı API'nin nasıl etkileşimde olduğu gösterilmektedir:

flowchart LR
  A[User Browser] -->|1 Login OIDC| B[Blazor Server<br/>MyService.Web]
  B -->|2 Redirect| C[Microsoft Entra ID]
  C -->|3 auth code| B
  B -->|4 exchange auth code| C
  C -->|5 tokens| B
  B -->|6 cookie + session| A
  B -->|7 HTTP + Bearer token| D[ASP.NET API<br/>MyService.ApiService<br/>Microsoft.Identity.Web]
  D -->|8 Validate JWT| C
  D -->|9 Weather data| B
  1. Kullanıcı Blazor uygulamasını ziyaret eder → Kimliği doğrulanmamış → "Giriş Yap" düğmesini görür.
  2. Kullanıcı Giriş’i seçer/authentication/login → OIDC challenge → Microsoft Entra'ya yönlendirir.
  3. User oturum açar → Microsoft Entra /signin-oidc → tanımlama bilgisine yönlendirilir.
  4. Kullanıcı Hava Durumu sayfasına gider → Blazor çağrısı.
  5. MicrosoftIdentityMessageHandler isteği engeller, önbellekten bir belirteç alır (veya sessizce yeniler) ve Authorization: Bearer <token> üst bilgiyi ekler.
  6. API isteği alır → Microsoft.Identity.Web, JWT'yi doğrular → verileri döndürür.
  7. Blazor hava durumu verilerini işler.

Çözüm yapısını gözden geçirme

Aspire starter şablonu aşağıdaki proje düzenini oluşturur:

MyService/
├── MyService.AppHost/           # Aspire orchestration
├── MyService.ApiService/        # Protected API (Microsoft.Identity.Web)
├── MyService.Web/               # Blazor Server (Microsoft.Identity.Web)
├── MyService.ServiceDefaults/   # Shared defaults
└── MyService.Tests/             # Tests

1. Bölüm: Microsoft ile API arka ucu güvenliğini sağlayın. Identity.Web

Bu bölümde API projesi, Microsoft Entra tarafından verilen JWT Taşıyıcı belirteçlerini doğrulayacak şekilde yapılandırılır.

Microsoft.Identity.Web paketini ekleyin

Microsoft.Identity.Web NuGet paketini yüklemek için aşağıdaki komutu çalıştırın.

cd MyService.ApiService
dotnet add package Microsoft.Identity.Web

Microsoft Entra ayarlarını yapılandırma

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

{
  "AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "TenantId": "<your-tenant-id>",
    "ClientId": "<your-api-client-id>",
    "Audiences": [
      "api://<your-api-client-id>"
    ]
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*"
}

Önemli özellikler:

  • ClientId: Microsoft Entra API uygulama kayıt kimliği
  • TenantId: Microsoft Entra kiracı kimliğiniz veya çok kiracılı kiracı için "organizations" veya herhangi bir Microsoft hesabı için "common"
  • Audiences: Geçerli jeton kitleleri (genellikle Uygulama Kimliği URI'niz)

API Program.cs'yi güncelleştir

JWT Taşıyıcı kimlik doğrulaması eklemek ve uç noktaları korumak için içeriğini MyService.ApiService/Program.cs aşağıdaki kodla değiştirin:

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

var builder = WebApplication.CreateBuilder(args);

builder.AddServiceDefaults();

// Add Microsoft.Identity.Web JWT Bearer authentication
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd"));

builder.Services.AddProblemDetails();
builder.Services.AddOpenApi();
builder.Services.AddAuthorization();

var app = builder.Build();

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

if (app.Environment.IsDevelopment())
{
    app.MapOpenApi();
}

string[] summaries = ["Freezing", "Bracing", "Chilly", "Cool", "Mild",
    "Warm", "Balmy", "Hot", "Sweltering", "Scorching"];

app.MapGet("/", () =>
    "API service is running. Navigate to /weatherforecast to see sample data.");

app.MapGet("/weatherforecast", () =>
{
    var forecast = Enumerable.Range(1, 5).Select(index =>
        new WeatherForecast
        (
            DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
            Random.Shared.Next(-20, 55),
            summaries[Random.Shared.Next(summaries.Length)]
        ))
        .ToArray();
    return forecast;
})
.WithName("GetWeatherForecast")
.RequireAuthorization();

app.MapDefaultEndpoints();
app.Run();

record WeatherForecast(DateOnly Date, int TemperatureC, string? Summary)
{
    public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
}

Önemli değişiklikler:

  • JWT Taşıyıcı kimlik doğrulamayı AddMicrosoftIdentityWebApi ile kaydet
  • Ekle app.UseAuthentication() ve app.UseAuthorization() ara yazılım
  • .RequireAuthorization() korumalı uç noktalara uygula

Korumalı API'yi test edin

API'nin kimliği doğrulanmamış istekleri reddettiğini ve geçerli belirteçleri kabul ettiğini doğrulayın.

Belirteç olmadan istek gönderin:

curl https://localhost:<PORT>/weatherforecast
# Expected: 401 Unauthorized

Geçerli bir belirteçle istek gönderin:

curl -H "Authorization: Bearer <TOKEN>" https://localhost:<PORT>/weatherforecast
# Expected: 200 OK with weather data

Bölüm 2: Kimlik doğrulaması için Blazor ön ucu yapılandırma

Blazor Server uygulaması, Microsoft.Identity.Web'i şu amaçlarla kullanır:

  • Kullanıcıları OIDC ile oturum açın
  • API'yi çağırmak için erişim belirteçleri alma
  • Giden HTTP isteklerine belirteç ekleme

Microsoft.Identity.Web paketini ekleyin

Microsoft.Identity.Web NuGet paketini yüklemek için aşağıdaki komutu çalıştırın.

cd MyService.Web
dotnet add package Microsoft.Identity.Web

Microsoft Entra ayarlarını yapılandırma

Microsoft Entra yapılandırmasını ve aşağı akış API kapsamlarını MyService.Web/appsettings.json ekleyin:

{
  "AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "Domain": "<your-tenant>.onmicrosoft.com",
    "TenantId": "<tenant-guid>",
    "ClientId":  "<web-app-client-id>",
    "CallbackPath": "/signin-oidc",
    "ClientCredentials": [
      {
        "SourceType": "ClientSecret",
        "ClientSecret": "<your-client-secret>"
      }
    ]
  },
  "WeatherApi": {
    "Scopes": [ "api://<api-client-id>/.default" ]
  },
  "Logging": {
    "LogLevel":  {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*"
}

Yapılandırma ayrıntıları:

  • ClientId: Web uygulaması kayıt kimliği (API kimliği değil)
  • ClientCredentials: Jetonları almak için web uygulamasının kimlik bilgileri. Birden çok kimlik bilgisi türünü destekler. Üretime hazır seçenekler için bkz. Kimlik bilgilerine genel bakış .
  • Scopes: Tarafından belirtilen sonekle API'nin Uygulama Kimliği URI'si eşleşmelidir /.default

Uyarı

Üretim için istemci gizli anahtarları yerine sertifikalar veya yönetilen kimlik kullanın. Önerilen yaklaşım için bkz. Sertifikasız kimlik doğrulaması .

Web uygulaması Program.cs güncelleştirme

OIDC kimlik doğrulamasını, belirteç alımını ve aşağıdaki API istemcisini yapılandırmak için MyService.Web/Program.cs içeriğini aşağıdaki kodla değiştirin:

using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.Identity.Abstractions;
using Microsoft.Identity.Web;
using MyService.Web;
using MyService.Web.Components;

var builder = WebApplication.CreateBuilder(args);

builder.AddServiceDefaults();

// Authentication + Microsoft Identity Web
builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"))
    .EnableTokenAcquisitionToCallDownstreamApi()
    .AddInMemoryTokenCaches();

builder.Services.AddCascadingAuthenticationState();

// Blazor components
builder.Services.AddRazorComponents().AddInteractiveServerComponents();

// Blazor authentication challenge handler for incremental consent and Conditional Access
builder.Services.AddScoped<BlazorAuthenticationChallengeHandler>();

builder.Services.AddOutputCache();

// Downstream API client with MicrosoftIdentityMessageHandler
builder.Services.AddHttpClient<WeatherApiClient>(client =>
{
    // Aspire service discovery: resolves "apiservice" at runtime
    client.BaseAddress = new("https+http://apiservice");
})
.AddMicrosoftIdentityMessageHandler(builder.Configuration.GetSection("WeatherApi"));

var app = builder.Build();

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

app.UseHttpsRedirection();
app.UseAuthentication();
app.UseAuthorization();
app.UseAntiforgery();
app.UseOutputCache();

app.MapStaticAssets();
app.MapRazorComponents<App>()
   .AddInteractiveServerRenderMode();

// Login/Logout endpoints with incremental consent support
app.MapGroup("/authentication").MapLoginAndLogout();

app.MapDefaultEndpoints();
app.Run();

Önemli noktalar:

  • AddMicrosoftIdentityWebApp: OIDC kimlik doğrulamayı yapılandırıyor
  • EnableTokenAcquisitionToCallDownstreamApi: Alt API'ler için token alımını etkinleştirir
  • AddScoped<BlazorAuthenticationChallengeHandler>: Blazor Server'da artımlı onay ve Koşullu Erişim ile ilgilenir.
  • AddMicrosoftIdentityMessageHandler: HttpClient isteklerine taşıyıcı belirteçleri otomatik olarak ekler
  • https+http://apiservice: Aspire service discovery bunu gerçek API URL'sine çözümler
  • Ara yazılım sırası: UseAuthentication()UseAuthorization() → uç noktaları

Uzantı AddMicrosoftIdentityMessageHandler birden çok yapılandırma desenini destekler:

Seçenek 1: appsettings.json yapılandırma (daha önce gösterilmiştir)

.AddMicrosoftIdentityMessageHandler(builder.Configuration.GetSection("WeatherApi"));

2. Seçenek: Eylem temsilcisiyle satır içi yapılandırma

.AddMicrosoftIdentityMessageHandler(options =>
{
    options.Scopes.Add("api://<api-client-id>/.default");
});

Seçenek 3: İstek başına yapılandırma (parametresiz)

.AddMicrosoftIdentityMessageHandler();

// Then in your service, configure per-request:
var request = new HttpRequestMessage(HttpMethod.Get, "/weatherforecast")
    .WithAuthenticationOptions(options =>
    {
        options.Scopes.Add("api://<api-client-id>/.default");
    });
var response = await _httpClient.SendAsync(request);

Blazor UI bileşenleri ekleme

Önemli

Bu adım sık sık unutulur. UserInfo bileşeni olmadan kullanıcıların oturum açma yolu yoktur.

BlazorAuthenticationChallengeHandler ve LoginLogoutEndpointRouteBuilderExtensionsMicrosoft.Identity.Web v3.3.0+ içinde sunulmaktadır. Pakete başvurdıktan sonra otomatik olarak kullanılabilirler; dosya kopyalama gerekmez.

Oluştur MyService.Web/Components/UserInfo.razor:

@using Microsoft.AspNetCore.Components.Authorization

<AuthorizeView>
    <Authorized>
        <span class="nav-item">Hello, @context.User.Identity?.Name</span>
        <form action="/authentication/logout" method="post" class="nav-item">
            <AntiforgeryToken />
            <input type="hidden" name="returnUrl" value="/" />
            <button type="submit" class="btn btn-link nav-link">Logout</button>
        </form>
    </Authorized>
    <NotAuthorized>
        <a href="/authentication/login?returnUrl=/" class="nav-link">Login</a>
    </NotAuthorized>
</AuthorizeView>

Düzene ekle: şunlarınıza dahil edin <UserInfo />MainLayout.razor:

@inherits LayoutComponentBase

<div class="page">
    <div class="sidebar">
        <NavMenu />
    </div>

    <main>
        <div class="top-row px-4">
            <UserInfo />
        </div>

        <article class="content px-4">
            @Body
        </article>
    </main>
</div>

AuthorizeRouteView için Routes.razor dosyasını güncelleştirme

RouteView ifadesindeki AuthorizeRouteView'i Components/Routes.razor ile değiştirin.

@using Microsoft.AspNetCore.Components.Authorization

<Router AppAssembly="typeof(Program).Assembly">
    <Found Context="routeData">
        <AuthorizeRouteView RouteData="routeData" DefaultLayout="typeof(Layout.MainLayout)">
            <NotAuthorized>
                <p>You are not authorized to view this page.</p>
                <a href="/authentication/login">Login</a>
            </NotAuthorized>
        </AuthorizeRouteView>
        <FocusOnNavigate RouteData="routeData" Selector="h1" />
    </Found>
</Router>

API'leri çağıran sayfalardaki özel durumları işleme

Blazor Sunucusu, Koşullu Erişim ve onay için açık özel durum işleme gerektirir. Uygulamanız önceden yetkilendirilmemiş ve tüm kapsamları MicrosoftIdentityWebChallengeUserException içinde önceden istemiyorsanız, aşağı akış API'sini çağıran her sayfada Program.cs işlemeniz gerekir.

Aşağıdaki Weather.razor örnekte uygun özel durum işleme gösterilmektedir:

@page "/weather"
@attribute [Authorize]

@using Microsoft.AspNetCore.Authorization
@using Microsoft.Identity.Web

@inject WeatherApiClient WeatherApi
@inject BlazorAuthenticationChallengeHandler ChallengeHandler

<PageTitle>Weather</PageTitle>

<h1>Weather</h1>

@if (!string.IsNullOrEmpty(errorMessage))
{
    <div class="alert alert-warning">@errorMessage</div>
}
else if (forecasts == null)
{
    <p><em>Loading...</em></p>
}
else
{
    <table class="table">
        <thead>
            <tr>
                <th>Date</th>
                <th>Temp. (C)</th>
                <th>Summary</th>
            </tr>
        </thead>
        <tbody>
            @foreach (var forecast in forecasts)
            {
                <tr>
                    <td>@forecast.Date.ToShortDateString()</td>
                    <td>@forecast.TemperatureC</td>
                    <td>@forecast.Summary</td>
                </tr>
            }
        </tbody>
    </table>
}

@code {
    private WeatherForecast[]? forecasts;
    private string? errorMessage;

    protected override async Task OnInitializedAsync()
    {
        if (!await ChallengeHandler.IsAuthenticatedAsync())
        {
            await ChallengeHandler.ChallengeUserWithConfiguredScopesAsync("WeatherApi:Scopes");
            return;
        }

        try
        {
            forecasts = await WeatherApi.GetWeatherAsync();
        }
        catch (Exception ex)
        {
            // Handle incremental consent / Conditional Access
            if (!await ChallengeHandler.HandleExceptionAsync(ex))
            {
                errorMessage = $"Error loading weather data: {ex.Message}";
            }
        }
    }
}

Desen aşağıdaki gibi çalışır:

  1. IsAuthenticatedAsync() API çağrıları yapmadan önce kullanıcının oturum açmış olup olmadığını denetler.
  2. HandleExceptionAsync() MicrosoftIdentityWebChallengeUserException'i yakalar (ya da InnerException olarak yakalar).
  3. Eğer bu bir challenge istisnasıysa, kullanıcı gerekli talepler veya kapsamlarla yeniden kimlik doğrulaması yapmak üzere yeniden yönlendirilir.
  4. Bu bir sınama özel durumu değilse, HandleExceptionAsync hatayı kendiniz işleyebilmeniz için döndürür false .

İstemci gizli anahtarını kullanıcı gizli anahtarlarında depolayın.

Geliştirme sırasında istemci sırrını güvenli bir şekilde depolamak için .NET Gizli Yöneticisi'ni kullanın.

Dikkat

Gizli bilgileri hiçbir zaman kaynak denetimine işlemeyin.

Kullanıcı gizliliğini başlatın ve istemci sırrını depolayın.

cd MyService.Web
dotnet user-secrets init
dotnet user-secrets set "AzureAd:ClientCredentials:0:ClientSecret" "<your-client-secret>"

Ardından sabit kodlanmış gizliyi kaldırmak için appsettings.json'yi güncelleyin

{
  "AzureAd": {
    "ClientCredentials": [
      {
        "SourceType": "ClientSecret"
      }
    ]
  }
}

Microsoft. Identity.Web birden çok kimlik bilgisi türünü destekler. Üretim için bkz. Kimlik bilgilerine genel bakış.


Uygulamayı doğrulama

Tüm gerekli adımları tamamladığınızdan emin olmak için bu denetim listesini kullanın.

API projesi

  • [ ] Microsoft.Identity.Web paketi eklendi
  • [ ] appsettings.json, AzureAd bölümüyle güncellendi
  • [ ] Program.csAddMicrosoftIdentityWebApi ile güncellendi
  • [ ] Korumalı uç noktalara eklendi .RequireAuthorization()

Web/Blazor projesi

  • [ ] Microsoft.Identity.Web paketi eklendi (v3.3.0+)
  • [ ] appsettings.json ve AzureAd ve WeatherApi bölümleriyle güncellendi
  • [ ] OIDC, belirteç edinimi ile güncellenmiştir Program.cs
  • [ ] Eklendi AddScoped<BlazorAuthenticationChallengeHandler>()
  • [ ] Oluşturuldu Components/UserInfo.razor (oturum açma düğmesi)
  • [c0 /> MainLayout.razor'i içine alacak şekilde güncellendi.]
  • [ ] Routes.razorAuthorizeRouteView ile güncellendi
  • [ ] API'leri çağıran her sayfaya try/catch eklendi ChallengeHandler
  • [ ] İstemci gizli anahtarı, user-secrets'te depolandı.

Verification

  • [ ] dotnet build başarılı
  • [ ] Microsoft Entra yönetim merkezinde oluşturulan uygulama kayıtları
  • [ ] appsettings.json gerçek GUID'lere sahip (yer tutucu yok)

Test ve sorun giderme

Uygulamayı tamamladıktan sonra uygulamayı çalıştırın ve uçtan uca kimlik doğrulama akışını doğrulayın.

Uygulamayı çalıştırma

Hem web hem de API projelerini başlatmak için Aspire AppHost'ı başlatın:

# From solution root
dotnet restore
dotnet build

# Launch AppHost (starts both Web and API)
dotnet run --project .\MyService.AppHost\MyService.AppHost.csproj

Kimlik doğrulama akışını test edin

  1. Blazor Web kullanıcı arabirimi → tarayıcıyı açın (URL için Aspire panosunu denetleyin).
  2. Login → Microsoft Entra ile oturum aç'ı seçin.
  3. Hava Durumu sayfasına gidin.
  4. Hava durumu veri yüklerini doğrulayın (korumalı API'den).

Sık karşılaşılan sorunları çözme

Aşağıdaki tabloda sık karşılaşılan sorunlar ve bunların çözümleri listelenir:

Sorun Çözüm
API çağrılarında 401 içindeki appsettings.json kapsamların API'nin Uygulama Kimliği URI'sine uygun olduğunu doğrulayın
OIDC yeniden yönlendirmesi başarısız oluyor Microsoft Entra yeniden yönlendirme URI'lerine /signin-oidc ekleyin
Belirteç eklenmedi AddMicrosoftIdentityMessageHandler öğesinin HttpClient üzerinde çağrıldığından emin olun
Hizmet bulma başarısız oluyor Her iki projeyi ve onların çalışır durumda olduğunu kontrol edin AppHost.cs
AADSTS65001 Yönetici onayı gerekli — Microsoft Entra yönetim merkezinde onay verin
Oturum açma düğmesi yok UserInfo.razor mevcut olduğundan ve MainLayout.razor dahil edildiğinden emin olun.
Onay döngüsü Try/catch ile HandleExceptionAsync komutunun tüm API çağrı sayfalarında olduğundan emin olun

MSAL günlüğünü etkinleştirme

Kimlik doğrulama sorunlarını giderirken, belirteç edinme ayrıntılarını görmek için ayrıntılı MSAL günlüğünü etkinleştirin. Aşağıdaki günlük düzeylerini appsettings.json içine ekleyin:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning",
      "Microsoft.Identity": "Debug",
      "Microsoft.IdentityModel": "Debug"
    }
  }
}

Uyarı

Çok ayrıntılı olabileceği için üretimde hata ayıklama günlüğünü devre dışı bırakın.

Tokenları denetle

Belirteç sorunlarını gidermek için JWT'nizi jwt.ms adresinde çözümleyin ve şunları doğrulayın:

  • aud (hedef kitle): API'nizin İstemci Kimliği veya Uygulama Kimliği URI'si ile eşleşir
  • iss (veren): Kiracınızla eşleşir (https://login.microsoftonline.com/<tenant-id>/v2.0)
  • scp (kapsamlar): Gerekli kapsamları içerir
  • exp (token süresi dolmadı): Token henüz süresi dolmadı

Yaygın senaryoları keşfetme

Aşağıdaki bölümlerde, ek kullanım örnekleri için temel uygulamanın nasıl genişlet kullanılacağı gösterilmektedir.

Blazor sayfalarını koruma

[Authorize] Kimlik doğrulaması gerektiren sayfalara özniteliğini ekleyin:

@page "/weather"
@attribute [Authorize]

veya Program.cs içinde yetkilendirme ilkelerini tanımlayın:

// Program.cs
builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("AdminOnly", policy => policy.RequireRole("Admin"));
});
@attribute [Authorize(Policy = "AdminOnly")]

API'de kapsamları doğrulama

API'nin yalnızca belirli kapsamları olan belirteçleri kabul etmesini RequireScope zincirleyerek sağlayın.

app.MapGet("/weatherforecast", () =>
{
    // ... implementation
})
.RequireAuthorization()
.RequireScope("access_as_user");

Uygulama öncelikli belirteçler kullanın (servisler arası)

Daemon senaryoları veya kullanıcı bağlamı olmayan hizmet-hizmet çağrıları için, RequestAppToken öğesini true olarak ayarlayın.

builder.Services.AddHttpClient<WeatherApiClient>(client =>
{
    client.BaseAddress = new("https+http://apiservice");
})
.AddMicrosoftIdentityMessageHandler(options =>
{
    options.Scopes.Add("api://<api-client-id>/.default");
    options.RequestAppToken = true;
});

Üretim için sertifikasız kimlik bilgilerini kullanma

Azure'daki üretim dağıtımları için istemci sırları yerine yönetilen kimlik kullanılması önerilir. ClientCredentials Bölümü aşağıdaki gibi yapılandırın:

{
  "AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "TenantId": "<tenant-guid>",
    "ClientId":  "<web-app-client-id>",
    "ClientCredentials": [
      {
        "SourceType": "SignedAssertionFromManagedIdentity",
        "ManagedIdentityClientId": "<user-assigned-mi-client-id>"
      }
    ]
  }
}

Daha fazla bilgi için bkz. Sertifikasız kimlik doğrulaması.

API'den alt düzey API'leri, başka birinin adına çağırma

API'nizin kullanıcı adına başka bir alt API'yi çağırması gerekiyorsa, Program.cs içinde adına belirteç alımını etkinleştirin.

// MyService.ApiService/Program.cs
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd"))
    .EnableTokenAcquisitionToCallDownstreamApi()
    .AddInMemoryTokenCaches();

builder.Services.AddDownstreamApi("GraphApi", builder.Configuration.GetSection("GraphApi"));

Aşağı akış API yapılandırmasını appsettings.json ekleyin:

{
  "GraphApi": {
    "BaseUrl": "https://graph.microsoft.com/v1.0",
    "Scopes": [ "User.Read" ]
  }
}

Ardından bir uç noktadan aşağı akış API'sini çağırın:

{
    var user = await downstreamApi.GetForUserAsync<JsonElement>("GraphApi", "me");
    return user;
}).RequireAuthorization();

Daha fazla bilgi için bkz. Aşağı akış API'lerini çağırma.