Buat aplikasi daemon dan identitas agen dengan Microsoft. Identity.Web

Dalam artikel ini, Anda membangun aplikasi daemon, layanan latar belakang, dan agen otonom menggunakan Microsoft. Identity.Web. Aplikasi ini berjalan tanpa interaksi pengguna dan mengautentikasi menggunakan identitas aplikasi (kredensial klien) atau identitas agen.

Memahami skenario yang didukung

Microsoft. Identity.Web mendukung tiga jenis aplikasi non-interaktif:

Skenario Jenis Autentikasi Jenis Token Kasus Penggunaan
Daemon Standar Kredensial klien (rahasia/sertifikat) Token akses khusus aplikasi Layanan latar belakang, pekerjaan terjadwal, pemrosesan data
Agen Otonom Identitas agen dengan kredensial klien Token akses khusus aplikasi untuk agen Agen copilot, layanan otonom yang bertindak atas nama identitas agen. (Biasanya dalam API Web yang dilindungi)
Identitas Pengguna Agen Identitas agen pengguna Identitas pengguna agen dengan kredensial klien Layanan otonom yang bertindak atas nama identitas Pengguna Agen. (Biasanya dalam API Web yang dilindungi)

Memulai

Prasyarat

Sebelum mulai, pastikan bahwa Anda memiliki:

  • .NET 8.0 atau yang lebih baru
  • Pendaftaran aplikasi Microsoft Entra dengan kredensial klien (rahasia klien atau sertifikat)
  • Dalam skenario agen: Identitas agen yang dikonfigurasi di tenant Microsoft Entra Anda

Memasang paket

Tambahkan paket NuGet yang diperlukan ke proyek Anda:

dotnet add package Microsoft.Identity.Web
dotnet add package Microsoft.Extensions.Hosting

Memilih pendekatan konfigurasi

Microsoft. Identity.Web menyediakan dua cara untuk mengonfigurasi aplikasi daemon:

Terbaik untuk: Prototipe cepat, aplikasi konsol, pengujian, dan layanan daemon sederhana.

Kode berikut membuat TokenAcquirerFactory, mengonfigurasi API hilir dan Microsoft Graph, dan memanggil Graph API:

using Microsoft.Identity.Abstractions;
using Microsoft.Identity.Web;

// Get the token acquirer factory instance
var tokenAcquirerFactory = TokenAcquirerFactory.GetDefaultInstance();

// Configure downstream API and Microsoft Graph (optional)
tokenAcquirerFactory.Services.AddDownstreamApis(
    tokenAcquirerFactory.Configuration.GetSection("DownstreamApis"))
    .AddMicrosoftGraph();

var serviceProvider = tokenAcquirerFactory.Build();

// Call Microsoft Graph
var graphClient = serviceProvider.GetRequiredService<GraphServiceClient>();
var users = await graphClient.Users.GetAsync();

Keuntungan:

  • Boilerplate code yang minimal
  • Memuat secara otomatis appsettings.json
  • Sempurna untuk skenario sederhana
  • Inisialisasi dalam satu baris

Kekurangan:

  • Tidak cocok untuk pengujian yang berjalan secara paralel (singleton)

Terbaik untuk: Aplikasi produksi, skenario kompleks, injeksi dependensi, kemampuan uji coba.

Kode berikut menggunakan Host Generik .NET untuk mengonfigurasi autentikasi, perolehan token, penyimpanan sementara, dan layanan latar belakang.

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Identity.Web;

var host = Host.CreateDefaultBuilder(args)
    .ConfigureServices((context, services) =>
    {
        // Configure authentication
        services.Configure<MicrosoftIdentityApplicationOptions>(
            context.Configuration.GetSection("AzureAd"));

        // Add token acquisition (true = singleton lifetime)
        services.AddTokenAcquisition(true);

        // Add token cache (in-memory for development)
        services.AddInMemoryTokenCaches();

        // Add HTTP client for API calls
        services.AddHttpClient();

        // Add Microsoft Graph (optional)
        services.AddMicrosoftGraph();

        // Add your background service
        services.AddHostedService<DaemonWorker>();
    })
    .Build();

await host.RunAsync();

Keuntungan:

  • Kontrol penuh atas penyedia konfigurasi
  • Uji coba yang lebih baik dengan injeksi konstruktor
  • Terintegrasi dengan model hosting ASP.NET Core
  • Mendukung skenario kompleks (beberapa skema autentikasi)
  • Arsitektur siap produksi
  • Mendukung eksekusi pengujian paralel (penyedia layanan terisolasi per pengujian)

Nota

Parameter true di AddTokenAcquisition(true) berarti layanan terdaftar sebagai singleton (satu instance untuk masa pakai aplikasi). Gunakan false untuk masa pakai terlingkup dalam aplikasi web.

Rekomendasi: Mulailah dengan TokenAcquirerFactory untuk prototipe dan pengujian utas tunggal. Migrasikan ke pola penuh ServiceCollection saat membangun aplikasi produksi atau menjalankan pengujian paralel.


Mengonfigurasi aplikasi daemon standar

Aplikasi daemon standar mengautentikasi menggunakan kredensial klien (rahasia klien atau sertifikat) dan mendapatkan token akses khusus aplikasi untuk memanggil API.

Konfigurasikan pengaturan otentikasi

Tambahkan konfigurasi berikut ke file appsettings.json Anda. Anda dapat menggunakan rahasia klien atau sertifikat (disarankan untuk produksi):

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

    "ClientSecret": "your-client-secret",

    "ClientCredentials": [
      // Option 1: Client Secret
      {
        "SourceType": "ClientSecret",
        "ClientSecret": "your-client-secret",
      },
      // Option 2: Certificate (recommended for production)
      {
        "SourceType": "StoreWithDistinguishedName",
        "CertificateStorePath": "CurrentUser/My",
        "CertificateDistinguishedName": "CN=DaemonAppCert"
      }
      // More options: https://aka.ms/ms-id-web/client-credentials
    ]
  }
}

Penting: Atur appsettings.json Anda untuk menyalin ke direktori output. Tambahkan yang berikut ini ke file Anda .csproj :

<ItemGroup>
  <None Update="appsettings.json">
    <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
  </None>
</ItemGroup>

ASP.NET Core aplikasi menyalin file ini secara otomatis, tetapi aplikasi daemon (dan aplikasi OWIN) tidak.

Menyiapkan konfigurasi layanan

Kode Program.cs berikut mendaftarkan opsi identitas Microsoft, perolehan token, cache, dan layanan latar belakang yang dihosting.

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Identity.Web;

var host = Host.CreateDefaultBuilder(args)
    .ConfigureServices((context, services) =>
    {
        IConfiguration configuration = context.Configuration;

        // Configure Microsoft Identity options
        services.Configure<MicrosoftIdentityApplicationOptions>(
            configuration.GetSection("AzureAd"));

        // Add token acquisition (true = singleton)
        services.AddTokenAcquisition(true);

        // Add token cache
        services.AddInMemoryTokenCaches(); // For development
        // services.AddDistributedTokenCaches(); // For production

        // Add HTTP client
        services.AddHttpClient();

        // Add Microsoft Graph SDK (optional)
        services.AddMicrosoftGraph();

        // Add your background service
        services.AddHostedService<DaemonWorker>();
    })
    .Build();

await host.RunAsync();

Memanggil Microsoft Graph

Kelas DaemonWorker.cs berikut menggunakan Graph SDK untuk mencantumkan pengguna pada jadwal berulang:

using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Graph;
using Microsoft.Identity.Abstractions;

public class DaemonWorker : BackgroundService
{
    private readonly GraphServiceClient _graphClient;
    private readonly ILogger<DaemonWorker> _logger;

    public DaemonWorker(
        GraphServiceClient graphClient,
        ILogger<DaemonWorker> logger)
    {
        _graphClient = graphClient;
        _logger = logger;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        while (!stoppingToken.IsCancellationRequested)
        {
            try
            {
                // Call Microsoft Graph with app-only permissions
                var users = await _graphClient.Users
                    .GetAsync(cancellationToken: stoppingToken);

                _logger.LogInformation($"Found {users?.Value?.Count} users");
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error calling Microsoft Graph");
            }

            await Task.Delay(TimeSpan.FromMinutes(5), stoppingToken);
        }
    }
}

Gunakan IAuthorizationHeaderProvider

Untuk kontrol lebih lanjut atas panggilan HTTP, gunakan IAuthorizationHeaderProvider untuk membuat header otorisasi secara manual:

using Microsoft.Identity.Abstractions;

public class DaemonService
{
    private readonly IAuthorizationHeaderProvider _authProvider;
    private readonly HttpClient _httpClient;

    public DaemonService(
        IAuthorizationHeaderProvider authProvider,
        IHttpClientFactory httpClientFactory)
    {
        _authProvider = authProvider;
        _httpClient = httpClientFactory.CreateClient();
    }

    public async Task<string> CallApiAsync()
    {
        // Get authorization header for app-only access
        string authHeader = await _authProvider
            .CreateAuthorizationHeaderForAppAsync(
                scopes: "https://graph.microsoft.com/.default");

        // Add to HTTP request
        _httpClient.DefaultRequestHeaders.Clear();
        _httpClient.DefaultRequestHeaders.Add("Authorization", authHeader);

        var response = await _httpClient.GetStringAsync(
            "https://graph.microsoft.com/v1.0/users");

        return response;
    }
}

Lihat juga Caling API hilir untuk mempelajari semua cara Microsoft Identity Web mengusulkan untuk memanggil API hilir.


Mengonfigurasi agen otonom (identitas agen)

Agen otonom menggunakan identitas agen untuk mendapatkan token khusus aplikasi. Pola ini berguna untuk skenario Copilot dan layanan otonom.

Nota

Microsoft menyarankan agar agen yang memanggil API hilir melakukannya dari dalam API web yang dilindungi, bahkan ketika agen memperoleh token aplikasi.

Mengonfigurasi layanan agen

Kode berikut menyiapkan autentikasi, akuisisi token, dan dukungan identitas agen menggunakan konfigurasi dalam memori:

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Configuration;
using Microsoft.Identity.Web;

var services = new ServiceCollection();

// Configuration
var configuration = new ConfigurationBuilder()
    .AddInMemoryCollection(new Dictionary<string, string?>
    {
        ["AzureAd:Instance"] = "https://login.microsoftonline.com/",
        ["AzureAd:TenantId"] = "your-tenant-id",
        ["AzureAd:ClientId"] = "your-agent-app-client-id",
        ["AzureAd:ClientCredentials:0:SourceType"] = "StoreWithDistinguishedName",
        ["AzureAd:ClientCredentials:0:CertificateStorePath"] = "CurrentUser/My",
        ["AzureAd:ClientCredentials:0:CertificateDistinguishedName"] = "CN=YourCert"
    })
    .Build();

services.AddSingleton<IConfiguration>(configuration);

// Configure Microsoft Identity
services.Configure<MicrosoftIdentityApplicationOptions>(
    configuration.GetSection("AzureAd"));

services.AddTokenAcquisition(true);
services.AddInMemoryTokenCaches();
services.AddHttpClient();
services.AddMicrosoftGraph();

// Add agent identities support
services.AddAgentIdentities();

var serviceProvider = services.BuildServiceProvider();

Memperoleh token dengan identitas agen

Setelah mengonfigurasi layanan agen, dapatkan token menggunakan IAuthorizationHeaderProvider atau SDK Microsoft Graph:

using Microsoft.Identity.Abstractions;
using Microsoft.Graph;

// Your agent identity GUID
string agentIdentityId = "d84da24a-2ea2-42b8-b5ab-8637ec208024";

// Option 1: Using IAuthorizationHeaderProvider
IAuthorizationHeaderProvider authProvider =
    serviceProvider.GetRequiredService<IAuthorizationHeaderProvider>();

var options = new AuthorizationHeaderProviderOptions()
    .WithAgentIdentity(agentIdentityId);

string authHeader = await authProvider.CreateAuthorizationHeaderForAppAsync(
    scopes: "https://graph.microsoft.com/.default",
    options);

// Option 2: Using Microsoft Graph SDK
GraphServiceClient graphClient =
    serviceProvider.GetRequiredService<GraphServiceClient>();

var applications = await graphClient.Applications.GetAsync(request =>
{
    request.Options.WithAuthenticationOptions(authOptions =>
    {
        authOptions.WithAgentIdentity(agentIdentityId);
    });
});

Meninjau contoh agen otonom lengkap

Kelas berikut membungkus akuisisi token identitas agen dan panggilan Graph API ke dalam layanan yang dapat digunakan kembali:

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Configuration;
using Microsoft.Graph;
using Microsoft.Identity.Abstractions;
using Microsoft.Identity.Web;

public class AutonomousAgentService
{
    private readonly GraphServiceClient _graphClient;
    private readonly IAuthorizationHeaderProvider _authProvider;
    private readonly string _agentIdentityId;

    public AutonomousAgentService(
        string agentIdentityId,
        IServiceProvider serviceProvider)
    {
        _agentIdentityId = agentIdentityId;
        _graphClient = serviceProvider.GetRequiredService<GraphServiceClient>();
        _authProvider = serviceProvider.GetRequiredService<IAuthorizationHeaderProvider>();
    }

    public async Task<string> GetAuthorizationHeaderAsync()
    {
        var options = new AuthorizationHeaderProviderOptions()
            .WithAgentIdentity(_agentIdentityId);

        return await _authProvider.CreateAuthorizationHeaderForAppAsync(
            "https://graph.microsoft.com/.default",
            options);
    }

    public async Task<IEnumerable<Application>> ListApplicationsAsync()
    {
        var apps = await _graphClient.Applications.GetAsync(request =>
        {
            request.Options.WithAuthenticationOptions(options =>
            {
                options.WithAgentIdentity(_agentIdentityId);
            });
        });

        return apps?.Value ?? Enumerable.Empty<Application>();
    }
}

Mengonfigurasi identitas pengguna agen

Identitas pengguna agen memungkinkan agen untuk bertindak atas nama pengguna agen dengan izin yang didelegasikan. Gunakan pola ini untuk agen yang memerlukan kotak surat mereka sendiri atau sumber daya cakupan pengguna lainnya.

Prasyarat

Untuk menggunakan identitas pengguna agen, Anda memerlukan:

  • Cetak biru agen terdaftar di Microsoft Entra ID
  • Identitas agen dibuat dan ditautkan ke aplikasi agen
  • Identitas pengguna agen yang terkait dengan identitas agen

Mengonfigurasi layanan pengguna agen

Kode berikut mengonfigurasi identitas aplikasi agen dengan kredensial sertifikat dan mendaftarkan layanan yang diperlukan:

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Identity.Web;
using System.Security.Cryptography.X509Certificates;

var services = new ServiceCollection();

// Configure agent application
services.Configure<MicrosoftIdentityApplicationOptions>(options =>
{
    options.Instance = "https://login.microsoftonline.com/";
    options.TenantId = "your-tenant-id";
    options.ClientId = "your-agent-app-client-id";

    // Use certificate for agent authentication
    options.ClientCredentials = new[]
    {
        CertificateDescription.FromStoreWithDistinguishedName(
            "CN=YourCertificate",
            StoreLocation.CurrentUser,
            StoreName.My)
    };
});

// Add services (true = singleton)
services.AddSingleton<IConfiguration>(new ConfigurationBuilder().Build());
services.AddTokenAcquisition(true);
services.AddInMemoryTokenCaches();
services.AddHttpClient();
services.AddMicrosoftGraph();
services.AddAgentIdentities();

var serviceProvider = services.BuildServiceProvider();

Memperoleh token pengguna dengan identitas agen

Anda dapat mengidentifikasi pengguna target berdasarkan UPN atau ID objek.

Menurut nama pengguna (UPN)

using Microsoft.Identity.Abstractions;
using Microsoft.Graph;

string agentIdentityId = "your-agent-identity-id";
string userUpn = "user@yourtenant.onmicrosoft.com";

// Get authorization header
IAuthorizationHeaderProvider authProvider =
    serviceProvider.GetRequiredService<IAuthorizationHeaderProvider>();

var options = new AuthorizationHeaderProviderOptions()
    .WithAgentUserIdentity(
        agentApplicationId: agentIdentityId,
        username: userUpn);

string authHeader = await authProvider.CreateAuthorizationHeaderForUserAsync(
    scopes: new[] { "https://graph.microsoft.com/.default" },
    options);

// Or use Microsoft Graph SDK
GraphServiceClient graphClient =
    serviceProvider.GetRequiredService<GraphServiceClient>();

var me = await graphClient.Me.GetAsync(request =>
{
    request.Options.WithAuthenticationOptions(options =>
        options.WithAgentUserIdentity(agentIdentityId, userUpn));
});

Menurut ID Objek pengguna

string agentIdentityId = "your-agent-identity-id";
Guid userObjectId = Guid.Parse("user-object-id");

var options = new AuthorizationHeaderProviderOptions()
    .WithAgentUserIdentity(
        agentApplicationId: agentIdentityId,
        userId: userObjectId);

string authHeader = await authProvider.CreateAuthorizationHeaderForUserAsync(
    scopes: new[] { "https://graph.microsoft.com/.default" },
    options);

// With Graph SDK
var me = await graphClient.Me.GetAsync(request =>
{
    request.Options.WithAuthenticationOptions(options =>
        options.WithAgentUserIdentity(agentIdentityId, userObjectId));
});

Menyimpan Sementara Token dengan ClaimsPrincipal

Untuk meningkatkan performa, simpan sementara token pengguna dengan mengoper instans ClaimsPrincipal. Panggilan pertama mengisi identitas pengguna dengan klaim uid dan utid, sedangkan panggilan berikutnya menggunakan kembali token yang di-cache.

using System.Security.Claims;
using Microsoft.Identity.Abstractions;

// First call - creates cache entry
ClaimsPrincipal userPrincipal = new ClaimsPrincipal();

string authHeader = await authProvider.CreateAuthorizationHeaderForUserAsync(
    scopes: new[] { "https://graph.microsoft.com/.default" },
    options,
    userPrincipal);

// ClaimsPrincipal now has uid and utid claims for caching
bool hasUserId = userPrincipal.HasClaim(c => c.Type == "uid");
bool hasTenantId = userPrincipal.HasClaim(c => c.Type == "utid");

// Subsequent calls - uses cache
authHeader = await authProvider.CreateAuthorizationHeaderForUserAsync(
    scopes: new[] { "https://graph.microsoft.com/.default" },
    options,
    userPrincipal); // Reuse the same principal

Mengambil alih penyewa

Untuk skenario multi-tenant, Anda dapat menggantikan tenant saat runtime. Ini berguna ketika aplikasi dikonfigurasi dengan "common" tetapi perlu menargetkan penyewa tertentu:

var options = new AuthorizationHeaderProviderOptions()
    .WithAgentUserIdentity(agentIdentityId, userUpn);

// Override tenant (useful when app is configured with "common")
options.AcquireTokenOptions.Tenant = "specific-tenant-id";

string authHeader = await authProvider.CreateAuthorizationHeaderForUserAsync(
    scopes: new[] { "https://graph.microsoft.com/.default" },
    options);

// With Graph SDK
var me = await graphClient.Me.GetAsync(request =>
{
    request.Options.WithAuthenticationOptions(options =>
    {
        options.WithAgentUserIdentity(agentIdentityId, userUpn);
        options.AcquireTokenOptions.Tenant = "specific-tenant-id";
    });
});

Meninjau contoh identitas pengguna agen lengkap

Kelas berikut menyediakan metode untuk mendapatkan profil pengguna dan header otorisasi menggunakan identitas pengguna agen:

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Graph;
using Microsoft.Identity.Abstractions;
using System.Security.Claims;

public class AgentUserService
{
    private readonly IAuthorizationHeaderProvider _authProvider;
    private readonly GraphServiceClient _graphClient;
    private readonly string _agentIdentityId;

    public AgentUserService(
        string agentIdentityId,
        IServiceProvider serviceProvider)
    {
        _agentIdentityId = agentIdentityId;
        _authProvider = serviceProvider.GetRequiredService<IAuthorizationHeaderProvider>();
        _graphClient = serviceProvider.GetRequiredService<GraphServiceClient>();
    }

    public async Task<User> GetUserProfileAsync(string userUpn)
    {
        var me = await _graphClient.Me.GetAsync(request =>
        {
            request.Options.WithAuthenticationOptions(options =>
                options.WithAgentUserIdentity(_agentIdentityId, userUpn));
        });

        return me!;
    }

    public async Task<User> GetUserProfileByIdAsync(Guid userObjectId)
    {
        var me = await _graphClient.Me.GetAsync(request =>
        {
            request.Options.WithAuthenticationOptions(options =>
                options.WithAgentUserIdentity(_agentIdentityId, userObjectId));
        });

        return me!;
    }

    public async Task<string> GetAuthHeaderForUserAsync(
        string userUpn,
        ClaimsPrincipal? cachedPrincipal = null)
    {
        var options = new AuthorizationHeaderProviderOptions()
            .WithAgentUserIdentity(_agentIdentityId, userUpn);

        return await _authProvider.CreateAuthorizationHeaderForUserAsync(
            scopes: new[] { "https://graph.microsoft.com/.default" },
            options,
            cachedPrincipal ?? new ClaimsPrincipal());
    }
}

Membuat konfigurasi layanan yang dapat digunakan kembali

Menentukan metode ekstensi

Buat metode ekstensi yang dapat digunakan kembali untuk merangkum konfigurasi identitas agen di seluruh aplikasi Anda:

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Identity.Web;
using Microsoft.Identity.Web.TokenCacheProviders.InMemory;

public static class ServiceCollectionExtensions
{
    public static IServiceProvider ConfigureServicesForAgentIdentities(
        this IServiceCollection services,
        IConfiguration configuration)
    {
        // Add configuration
        services.AddSingleton(configuration);

        // Configure Microsoft Identity options
        services.Configure<MicrosoftIdentityApplicationOptions>(
            configuration.GetSection("AzureAd"));

        services.AddTokenAcquisition(true);

        // Add token caching
        services.AddInMemoryTokenCaches();

        // Add HTTP client
        services.AddHttpClient();

        // Add Microsoft Graph (optional)
        services.AddMicrosoftGraph();

        // Add agent identities support
        services.AddAgentIdentities();

        return services.BuildServiceProvider();
    }
}

Menggunakan metode ekstensi

Panggil metode ekstensi untuk mengonfigurasi layanan dalam satu baris:

var services = new ServiceCollection();
var configuration = new ConfigurationBuilder()
    .AddJsonFile("appsettings.json")
    .Build();

var serviceProvider = services.ConfigureServicesForAgentIdentities(configuration);

Panggil API

Bagian ini menunjukkan cara memanggil API menggunakan masing-masing dari tiga pola autentikasi.

Memanggil Microsoft Graph

Contoh berikut menunjukkan panggilan Microsoft Graph sebagai daemon standar, agen otonom, dan identitas pengguna agen:

using Microsoft.Graph;

GraphServiceClient graphClient =
    serviceProvider.GetRequiredService<GraphServiceClient>();

// Standard daemon (app-only)
var users = await graphClient.Users.GetAsync();

// Autonomous agent (app-only with agent identity)
var apps = await graphClient.Applications.GetAsync(request =>
{
    request.Options.WithAuthenticationOptions(options =>
    {
        options.WithAgentIdentity("agent-identity-id");
        options.RequestAppToken = true;
    });
});

// Agent user identity (delegated with user context)
var me = await graphClient.Me.GetAsync(request =>
{
    request.Options.WithAuthenticationOptions(options =>
        options.WithAgentUserIdentity("agent-identity-id", "user@tenant.com"));
});

Memanggil API kustom dengan IDownstreamApi

Gunakan IDownstreamApi untuk memanggil API yang dilindungi Anda sendiri dengan salah satu dari tiga pola autentikasi:

using Microsoft.Identity.Abstractions;

IDownstreamApi downstreamApi =
    serviceProvider.GetRequiredService<IDownstreamApi>();

// Standard daemon
var result = await downstreamApi.GetForAppAsync<ApiResponse>(
    serviceName: "MyApi",
    options => options.RelativePath = "api/data");

// With agent identity
var result = await downstreamApi.GetForAppAsync<ApiResponse>(
    serviceName: "MyApi",
    options =>
    {
        options.RelativePath = "api/data";
        options.WithAgentIdentity("agent-identity-id");
    });

// Agent user identity
var result = await downstreamApi.GetForUserAsync<ApiResponse>(
    serviceName: "MyApi",
    options =>
    {
        options.RelativePath = "api/data";
        options.WithAgentUserIdentity("agent-identity-id", "user@tenant.com");
    });

Melakukan panggilan HTTP manual

Gunakan IAuthorizationHeaderProvider secara langsung saat Anda memerlukan kontrol penuh atas permintaan HTTP:

using Microsoft.Identity.Abstractions;

IAuthorizationHeaderProvider authProvider =
    serviceProvider.GetRequiredService<IAuthorizationHeaderProvider>();

HttpClient httpClient = new HttpClient();

// Standard daemon
string authHeader = await authProvider.CreateAuthorizationHeaderForAppAsync(
    "https://graph.microsoft.com/.default");

httpClient.DefaultRequestHeaders.Add("Authorization", authHeader);
var response = await httpClient.GetStringAsync("https://graph.microsoft.com/v1.0/users");

// With agent identity
var options = new AuthorizationHeaderProviderOptions()
    .WithAgentIdentity("agent-identity-id");

authHeader = await authProvider.CreateAuthorizationHeaderForAppAsync(
    "https://graph.microsoft.com/.default",
    options);

// Agent user identity
var userOptions = new AuthorizationHeaderProviderOptions()
    .WithAgentUserIdentity("agent-identity-id", "user@tenant.com");

authHeader = await authProvider.CreateAuthorizationHeaderForUserAsync(
    new[] { "https://graph.microsoft.com/.default" },
    userOptions);

Konfigurasi cache token

Pilih strategi penyimpanan sementara berdasarkan lingkungan Anda.

Pengembangan: Cache dalam memori

Gunakan caching in-memory untuk pengembangan dan pengujian lokal:

services.AddInMemoryTokenCaches();

Produksi: Cache terdistribusi

Untuk produksi, gunakan cache terdistribusi untuk mempertahankan token di seluruh mulai ulang aplikasi dan instans peluasan skala.

SQL Server

Simpan token dalam tabel SQL Server:

services.AddDistributedSqlServerCache(options =>
{
    options.ConnectionString = configuration["ConnectionStrings:TokenCache"];
    options.SchemaName = "dbo";
    options.TableName = "TokenCache";
});
services.AddDistributedTokenCaches();

Redis

Gunakan Redis untuk penyimpanan cache token berkinerja tinggi dan terdistribusi.

services.AddStackExchangeRedisCache(options =>
{
    options.Configuration = configuration["Redis:ConnectionString"];
    options.InstanceName = "TokenCache_";
});
services.AddDistributedTokenCaches();

Cosmos DB

Gunakan Cosmos DB untuk caching token yang terdistribusi secara global.

services.AddCosmosDbTokenCaches(options =>
{
    options.CosmosDbConnectionString = configuration["CosmosDb:ConnectionString"];
    options.DatabaseId = "TokenCache";
    options.ContainerId = "Tokens";
});

Pelajari lebih lanjut:Konfigurasi Cache Token


Menjelajahi contoh Azure

Microsoft menyediakan sampel yang menunjukkan pola aplikasi daemon.

Repositori sampel

active-directory-dotnetcore-daemon-v2

Repositori ini berisi beberapa skenario:

Sample Deskripsi Link
1-Call-MSGraph Panggilan daemon dasar Microsoft Graph dengan kredensial klien Lihat Sampel
2-Call-OwnApi Daemon memanggil API web anda sendiri yang dilindungi Lihat Sampel
3-Using-KeyVault Daemon menggunakan Azure Key Vault untuk penyimpanan sertifikat Lihat Sampel
4-Multi-Tenant Aplikasi daemon multi-tenant Lihat Sampel
5-Call-MSGraph-ManagedIdentity Daemon menggunakan Identitas Terkelola di Azure Lihat Sampel

Membandingkan pola sampel dengan pola produksi

Sampel Azure menggunakan untuk kesederhanaan—pendekatan yang direkomendasikan untuk aplikasi konsol sederhana, prototipe, dan pengujian . Panduan ini menunjukkan kedua pola:

pola TokenAcquirerFactory (Sampel Azure):

// Simple, perfect for prototypes and tests
var tokenAcquirerFactory = TokenAcquirerFactory.GetDefaultInstance();
tokenAcquirerFactory.Services.AddDownstreamApi("MyApi", ...);
var serviceProvider = tokenAcquirerFactory.Build();

Pola ServiceCollection Lengkap (Aplikasi untuk Produksi):

// More control, testable, follows DI best practices
var services = new ServiceCollection();
services.AddTokenAcquisition(true); // true = singleton
services.Configure<MicrosoftIdentityApplicationOptions>(...);
var serviceProvider = services.BuildServiceProvider();

Kapan menggunakan yang:

  • Menggunakan TokenAcquirerFactory untuk: Aplikasi konsol, prototipe cepat, pengujian unit, layanan daemon sederhana
  • Gunakan ServiceCollection untuk: Aplikasi produksi, integrasi ASP.NET Core, skenario DI kompleks, layanan latar belakang dengan IHostedService

Kedua pendekatan didukung penuh dan siap produksi. Pilih berdasarkan kompleksitas aplikasi dan kebutuhan integrasi Anda.


Memecahkan masalah kesalahan umum

AADSTS700016: Aplikasi tidak ditemukan

Menyebabkan: Tidak valid ClientId atau aplikasi tidak terdaftar di penyewa.

Solution: Verifikasi ClientId dalam konfigurasi Anda cocok dengan pendaftaran aplikasi Microsoft Entra Anda.

AADSTS7000215: Rahasia klien tidak valid

Menyebabkan: Rahasia klien salah, kedaluwarsa, atau tidak dikonfigurasi.

Solution:

  • Verifikasi rahasia di portal Azure sesuai dengan konfigurasi Anda
  • Periksa tanggal kedaluwarsa rahasia
  • Pertimbangkan untuk menggunakan sertifikat untuk produksi

AADSTS700027: Pernyataan klien berisi tanda tangan yang tidak valid

Menyebabkan: Sertifikat tidak ditemukan, kedaluwarsa, atau kunci privat tidak dapat diakses.

Solution:

  • Verifikasi sertifikat diinstal di penyimpanan sertifikat yang benar
  • Periksa nama pembeda sertifikat cocok dengan konfigurasi
  • Pastikan aplikasi memiliki izin untuk membaca kunci privat
  • Lihat Panduan Konfigurasi Sertifikat

AADSTS650052: Aplikasi memerlukan akses ke layanan

Menyebabkan: Izin API yang diperlukan tidak diberikan atau persetujuan admin hilang.

Solution:

  1. Navigasi ke portal Azure → Pendaftaran aplikasi → izin API → aplikasi Anda
  2. Tambahkan izin yang diperlukan (misalnya, User.Read.All untuk Microsoft Graph)
  3. Klik tombol "Berikan persetujuan admin"

Kesalahan identitas agen

AADSTS50105: Pengguna yang masuk tidak memiliki peran yang ditetapkan

Menyebabkan: Identitas agen tidak dikonfigurasi dengan benar atau tidak ditetapkan ke aplikasi.

Solution:

  • Verifikasi keberadaan identitas agen di Microsoft Entra ID
  • Pastikan identitas agen ditautkan ke aplikasi Anda
  • Periksa apakah identitas agen memiliki izin yang diperlukan

Token diperoleh tetapi dengan izin yang salah

Menyebabkan: Menggunakan identitas pengguna agen tetapi meminta izin aplikasi, atau sebaliknya.

Solution:

  • Untuk token khusus aplikasi: Gunakan CreateAuthorizationHeaderForAppAsync dengan WithAgentIdentity
  • Untuk token yang didelegasikan: Gunakan CreateAuthorizationHeaderForUserAsync dengan WithAgentUserIdentity
  • Pastikan izin API cocok dengan jenis token (aplikasi vs. didelegasikan)

Masalah penembolokan token

Masalah: Token tidak di-cache, yang memaksa akuisisi baru setiap kali.

Solution:

  • Untuk identitas pengguna agen: Gunakan kembali instans yang sama ClaimsPrincipal di seluruh panggilan
  • Memverifikasi koneksi cache terdistribusi (jika menggunakan Redis/SQL)
  • Mengaktifkan pengelogan debug untuk melihat operasi cache

Diagnostik terperinci:Panduan Pencatatan dan Diagnostik