Erstellen Sie Daemonanwendungen und Agentidentitäten mit Microsoft. Identity.Web

In diesem Artikel erstellen Sie Daemonanwendungen, Hintergrunddienste und autonome Agents mit Microsoft. Identity.Web. Diese Anwendungen werden ohne Benutzerinteraktion ausgeführt und mithilfe von Anwendungsidentitäten (Clientanmeldeinformationen) oder Agentidentitäten authentifiziert.

Verstehen der unterstützten Szenarien

Microsoft. Identity.Web unterstützt drei Arten von nicht interaktiven Anwendungen:

Szenario Authentifizierungstyp Tokentyp Anwendungsfall
Standarddaemon Client-Anmeldedaten (Client-Schlüssel/Zertifikat) Nur-App-Zugriffstoken Hintergrunddienste, geplante Aufträge, Datenverarbeitung
Autonomer Agent Agentenidentität mit Client-Anmeldeinformationen Nur-App-Zugriffstoken für Agent Copilot-Agenten, autonome Dienste, die im Namen einer Agentenidentität agieren. (In der Regel in einer geschützten Web-API)
Agent-Benutzeridentität Agent-Benutzeridentität Agent-Benutzeridentität mit Client-Anmeldedaten Autonome Dienste, die im Auftrag einer Agent-Benutzeridentität handeln. (In der Regel in einer geschützten Web-API)

Beginnen

Voraussetzungen

Bevor Sie beginnen, stellen Sie sicher, dass Sie folgendes haben:

  • .NET 8.0 oder höher
  • Microsoft Entra App-Registrierung mit client-Anmeldeinformationen (geheimer Clientschlüssel oder Zertifikat)
  • Für Agentenszenarien: Agentenidentitäten, die in Ihrem Microsoft Entra-Mandanten konfiguriert sind

Pakete installieren

Fügen Sie dem Projekt die erforderlichen NuGet-Pakete hinzu:

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

Auswählen eines Konfigurationsansatzes

Microsoft. Identity.Web bietet zwei Möglichkeiten zum Konfigurieren von Daemonanwendungen:

Am besten geeignet für: Schnelle Prototypen, Konsolen-Apps, Tests und einfache Daemon-Dienste.

Der folgende Code erstellt eine TokenAcquirerFactory, konfiguriert nachgeschaltete APIs und Microsoft Graph und ruft die Graph-API auf:

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

Vorteile:

  • Minimaler Textbausteincode
  • Lädt automatisch appsettings.json
  • Perfekt für einfache Szenarien
  • Einzeilige Initialisierung

Nachteile:

  • Nicht geeignet für das Ausführen von Tests in Parallelbetrieb (Singleton)

Am besten geeignet für: Produktionsanwendungen, komplexe Szenarien, Abhängigkeitsinjektion, Testbarkeit.

Der folgende Code verwendet den .NET Generic Host zum Konfigurieren der Authentifizierung, des Tokenerwerbs, des Zwischenspeicherns und eines Hintergrunddiensts:

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

Vorteile:

  • Vollzugriff auf Konfigurationsanbieter
  • Bessere Testbarkeit mit Konstruktorinjektion
  • Integriert sich mit dem ASP.NET Core Hosting-Modell
  • Unterstützt komplexe Szenarien (mehrere Authentifizierungsschemas)
  • Produktionsfähige Architektur
  • Unterstützt parallele Testausführung (isolierter Dienstanbieter pro Test)

Hinweis

Der Parameter true in AddTokenAcquisition(true) bedeutet, dass der Dienst als Singleton registriert wird (einzelne Instanz für die App-Lebensdauer). Verwenden Sie false für eine bereichsbezogene Lebensdauer in Webanwendungen.

Empfehlung: Beginnen Sie mit TokenAcquirerFactory Prototypen und Einzelthreadtests. Migrieren Sie zum vollständigen ServiceCollection Muster, wenn Sie Produktionsanwendungen erstellen oder parallele Tests ausführen.


Konfigurieren von Standarddaemonanwendungen

Standarddaemonanwendungen authentifizieren sich mithilfe von Clientanmeldeinformationen (geheimem Clientschlüssel oder Zertifikat) und rufen Nur-App-Zugriffstoken zum Aufrufen von APIs ab.

Konfigurieren von Authentifizierungseinstellungen

Fügen Sie der Datei appsettings.json die folgende Konfiguration hinzu. Sie können entweder einen geheimen Clientschlüssel oder ein Zertifikat verwenden (empfohlen für die Produktion):

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

Wichtig: Stellen Sie Ihr appsettings.json so ein, dass es in das Ausgabeverzeichnis kopiert wird. Fügen Sie Folgendes zu Ihrer .csproj-Datei hinzu:

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

ASP.NET Core Anwendungen kopieren diese Datei automatisch, aber Daemon-Apps (und OWIN-Apps) nicht.

Einrichten der Dienstkonfiguration

Der folgende Program.cs Code registriert Microsoft Identitätsoptionen, Tokenakquisition, Zwischenspeicherung und einen gehosteten Hintergrunddienst:

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

Microsoft Graph aufrufen

Die folgende DaemonWorker.cs Klasse verwendet das Graph SDK zum Auflisten von Benutzern in einem wiederkehrenden Zeitplan:

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

Verwenden von IAuthorizationHeaderProvider

Um mehr Kontrolle über HTTP-Aufrufe zu erhalten, verwenden Sie die Verwendung IAuthorizationHeaderProvider zum manuellen Erstellen von Autorisierungsheadern:

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

Siehe auch Calling downstream APIs um alle Möglichkeiten zu erfahren, wie Microsoft Identity Web schlägt vor, nachgeschaltete APIs aufzurufen.


Konfigurieren autonomer Agents (Agentidentität)

Autonome Agenten verwenden Agentidentitäten, um App-Only-Token abzurufen. Dieses Muster eignet sich für Copilot Szenarien und autonome Dienste.

Hinweis

Microsoft empfiehlt, dass Agents, die nachgeschaltete APIs aufrufen, dies in geschützten Web-APIs tun, auch wenn die Agents ein App-Token erwerben.

Konfigurieren von Agentdiensten

Der folgende Code richtet die Unterstützung für Authentifizierung, Tokenerfassung und Agentidentität mithilfe der In-Memory-Konfiguration ein:

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

Abrufen von Token mit Identität des Agents

Nachdem Sie die Agentdienste konfiguriert haben, können Sie Token entweder mit IAuthorizationHeaderProvider oder mithilfe des Microsoft Graph SDK abrufen.

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

Überprüfen eines vollständigen autonomen Agent-Beispiels

Die folgende Klasse umschließt den Erwerb von Agentidentitätstoken und Graph-API Aufrufe in einen wiederverwendbaren Dienst:

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

Konfigurieren der Agent-Benutzeridentität

Die Agent-Benutzeridentität ermöglicht Es Agents, im Auftrag eines Agentbenutzers mit delegierten Berechtigungen zu handeln. Verwenden Sie dieses Muster für Agents, die ein eigenes Postfach oder andere ressourcen mit Benutzerbereich benötigen.

Voraussetzungen

Um die Agent-Benutzeridentität zu verwenden, benötigen Sie Folgendes:

  • In Microsoft Entra ID registrierter Agent-Blueprint
  • Agentidentität erstellt und mit der Agentanwendung verknüpft
  • Agent-Benutzeridentität, die der Agentidentität zugeordnet ist

Konfigurieren von Agent-Benutzerdiensten

Der folgende Code konfiguriert die Agentanwendungsidentität mit zertifikatbasierten Anmeldeinformationen und registriert die erforderlichen Dienste:

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

Benutzertokens mit Agentidentität abrufen

Sie können den Zielbenutzer anhand des UPN oder der Objekt-ID identifizieren.

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

Nach Benutzerobjekt-ID

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

Cachetoken mit ClaimsPrincipal

Um eine bessere Leistung zu erzielen, können Sie Benutzertoken zwischenspeichern, indem Sie eine ClaimsPrincipal Instanz übergeben. Der erste Aufruf befüllt den Principal mit uid und utid Claims. Nachfolgende Aufrufe verwenden erneut das zwischengespeicherte Token.

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

Überschreiben des Mandanten

Für Szenarien mit mehreren Mandanten können Sie den Mandanten zur Laufzeit außer Kraft setzen. Dies ist nützlich, wenn die App mit "common" konfiguriert ist, aber auf einen bestimmten Mandanten ausgerichtet werden muss:

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

Überprüfen eines vollständigen Agent-Benutzeridentitätsbeispiels

Die folgende Klasse stellt Methoden zum Abrufen von Benutzerprofilen und Autorisierungsheadern mithilfe der Agent-Benutzeridentität bereit:

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

Erstellen einer wiederverwendbaren Dienstkonfiguration

Definieren einer Erweiterungsmethode

Erstellen Sie eine wiederverwendbare Erweiterungsmethode, um die Agentidentitätskonfiguration in Ihrer Anwendung zu kapseln:

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

Verwenden Sie die Erweiterungsmethode

Rufen Sie die Erweiterungsmethode auf, um Dienste in einer einzelnen Zeile zu konfigurieren:

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

var serviceProvider = services.ConfigureServicesForAgentIdentities(configuration);

Aufrufen von APIs

In diesem Abschnitt wird gezeigt, wie APIs mithilfe der drei Authentifizierungsmuster aufgerufen werden.

Microsoft Graph aufrufen

Die folgenden Beispiele veranschaulichen das Aufrufen von Microsoft Graph als Standarddaemon, einen autonomen Agent und eine Agent-Benutzeridentität:

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

Aufrufen benutzerdefinierter APIs mit IDownstreamApi

Verwenden Sie IDownstreamApi, um eines der drei Authentifizierungsmuster zu nutzen, um Ihre eigenen geschützten APIs aufzurufen.

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

Manuelle HTTP-Aufrufe durchführen

Verwenden Sie IAuthorizationHeaderProvider direkt, wenn Sie volle Kontrolle über HTTP-Anforderungen benötigen.

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

Tokenzwischenspeicherung konfigurieren

Wählen Sie eine Zwischenspeicherungsstrategie basierend auf Ihrer Umgebung aus.

Entwicklung: In-Memory-Zwischenspeicher

Verwenden Sie die Speicherzwischenspeicherung für lokale Entwicklung und Tests:

services.AddInMemoryTokenCaches();

Produktion: Verteilter Cache

Verwenden Sie für die Produktion einen verteilten Cache, um Token über App-Neustarts hinweg beizubehalten und das Hochskalieren von Instanzen zu unterstützen.

SQL Server

Speichern von Token in einer SQL Server Tabelle:

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

Redis

Verwenden Sie Redis für eine leistungsstarke, verteilte Tokenzwischenspeicherung:

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

Cosmos DB

Verwenden Sie Cosmos DB für global verteilte Tokenzwischenspeicherung:

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

Weitere Informationen:Tokencachekonfiguration


Erkunden Azure Beispiele

Microsoft stellt Beispiele bereit, die Daemon-App-Muster veranschaulichen.

Beispiel-Repository

active-directory-dotnetcore-daemon-v2

Dieses Repository enthält mehrere Szenarien:

Beispiel Beschreibung Verbinden
1-Call-MSGraph Grundlegender Daemon, der Microsoft Graph mit Client-Anmeldeinformationen aufruft View-Beispiel
2-Call-OwnApi Daemon aufruft Ihre eigene geschützte Web-API View-Beispiel
3-Using-KeyVault Daemon mit Azure Key Vault für den Zertifikatspeicher View-Beispiel
4-Multi-Tenant Daemonanwendung mit mehreren Mandanten View-Beispiel
5-Call-MSGraph-ManagedIdentity Daemon mit verwalteter Identität auf Azure View-Beispiel

Vergleichen von Beispielmustern mit Produktionsmustern

In den Azure Beispielen wird TokenAcquirerFactory.GetDefaultInstance() aus Gründen der Einfachheit verwendet– der empfohlene Ansatz für einfache Konsolenanwendungen, Prototypen und Tests. Diese Anleitung zeigt beide Muster:

TokenAcquirerFactory-Muster (Azure Beispiele):

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

Full ServiceCollection-Muster (Produktions-Apps):

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

Wann sollte welche verwendet werden:

  • Verwenden Sie TokenAcquirerFactory für: Konsolen-Apps, schnelle Prototypen, Unit-Tests, einfache Daemon-Dienste
  • Verwenden Sie ServiceCollection für: Produktionsanwendungen, ASP.NET Core-Integration, komplexe DI-Szenarien, Hintergrunddienste mit IHostedService

Beide Ansätze werden vollständig unterstützt und sind bereit für den Produktionseinsatz. Wählen Sie basierend auf den Komplexitäts- und Integrationsanforderungen Ihrer Anwendung aus.


Häufige Fehler beheben

AADSTS700016: Anwendung nicht gefunden

Ursache: Ungültige ClientId oder nicht im Mandanten registrierte Anwendung.

Solution: Überprüfen Sie, ob die ClientId in Ihrer Konfiguration ihrer Microsoft Entra App-Registrierung entspricht.

AADSTS7000215: Ungültiger geheimer Clientschlüssel

Ursache: Der geheime Clientschlüssel ist falsch, abgelaufen oder nicht konfiguriert.

Lösung:

  • Stellen Sie sicher, dass das Geheimnis im Azure-Portal Ihrer Konfiguration entspricht.
  • Ablaufdatum des geheimen Schlüssels überprüfen
  • Erwägen Sie die Verwendung von Zertifikaten für die Produktion

AADSTS700027: Client assertion enthält ungültige Signatur

Ursache: Zertifikat nicht gefunden, abgelaufen oder privater Schlüssel nicht zugänglich.

Lösung:

  • Überprüfen, ob das Zertifikat im richtigen Zertifikatspeicher installiert ist
  • Überprüfen, ob der Distinguished Name des Zertifikats mit der Konfiguration übereinstimmt.
  • Sicherstellen, dass die Anwendung über die Berechtigung zum Lesen eines privaten Schlüssels verfügt
  • Siehe Zertifikatkonfigurationshandbuch

AADSTS650052: Die App benötigt Zugriff auf einen Dienst.

Ursache: Erforderliche API-Berechtigungen fehlen oder die Administratorzustimmung fehlt.

Lösung:

  1. Navigieren Sie zu Azure-Portal → App-Registrierungen → Ihre App → API-Berechtigungen
  2. Hinzufügen erforderlicher Berechtigungen (z. B. User.Read.All für Microsoft Graph)
  3. Klicken Sie auf die Schaltfläche "Administratorzustimmung erteilen".

Agentidentitätsfehler

AADSTS50105: Der angemeldete Benutzer ist keiner Rolle zugewiesen.

Ursache: Die Agentidentität ist nicht ordnungsgemäß konfiguriert oder der Anwendung nicht zugewiesen.

Lösung:

  • Überprüfen, ob die Agentidentität in Microsoft Entra ID vorhanden ist
  • Sicherstellen, dass die Agentidentität mit Ihrer Anwendung verknüpft ist
  • Überprüfen, ob die Agentidentität über erforderliche Berechtigungen verfügt

Erworbene Token mit falschen Berechtigungen

Ursache: Verwenden der Agent-Benutzeridentität oder Anfordern von App-Berechtigungen, oder umgekehrt.

Lösung:

  • Für Nur-App-Token: Verwenden CreateAuthorizationHeaderForAppAsync mit WithAgentIdentity
  • Für delegierte Token: Verwenden CreateAuthorizationHeaderForUserAsync mit WithAgentUserIdentity
  • Stellen Sie sicher, dass API-Berechtigungen mit dem Tokentyp übereinstimmen (Anwendung im Vergleich zu delegierten)

Probleme beim Zwischenspeichern von Token

Problem: Token werden nicht zwischengespeichert, wodurch jedes Mal eine neue Übernahme erzwungen wird.

Lösung:

  • Für die Agent-Benutzeridentität: Dieselbe ClaimsPrincipal-Instanz bei Aufrufen wiederverwenden
  • Überprüfen der Verbindung mit verteilten Caches (bei Verwendung von Redis/SQL)
  • Aktivieren der Debugprotokollierung zum Anzeigen von Cachevorgängen

Detaillierte Diagnose:Protokollierungs- und Diagnosehandbuch