Crie aplicativos daemon e identidades de agente com Microsoft. Identity.Web

Neste artigo, você criará aplicativos daemon, serviços em segundo plano e agentes autônomos usando Microsoft. Identity.Web. Esses aplicativos são executados sem interação do usuário e autenticados usando identidade de aplicativo (credenciais de cliente) ou identidades de agente.

Entender cenários com suporte

Microsoft. O Identity.Web dá suporte a três tipos de aplicativos não interativos:

Cenário Tipo de Autenticação Tipo de token Caso de uso
Daemon Padrão Credenciais do cliente (segredo/certificado) Token de acesso exclusivo para aplicativo Serviços em segundo plano, trabalhos agendados, processamento de dados
Agente Autônomo Identidade do agente com credenciais de cliente Token de acesso somente para aplicativo do agente Agentes do Copilot, serviços autônomos que agem em nome de uma identidade de um agente. (Normalmente, em uma API Web protegida)
Identidade de Usuário do Agente Identidade do usuário do agente Identidade do agente usuário com credenciais de cliente Serviços autônomos atuando em nome de uma identidade de usuário-agente. (Normalmente, em uma API Web protegida)

Introdução

Pré-requisitos

Antes de começar, verifique se você tem:

  • .NET 8.0 ou posterior
  • Microsoft Entra registro de aplicativo com credenciais do cliente (segredo do cliente ou certificado)
  • Para cenários de agente: identidades de agentes configuradas em seu locatário Microsoft Entra

Instalar pacotes

Adicione os pacotes NuGet necessários ao seu projeto:

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

Escolher uma abordagem de configuração

Microsoft. O Identity.Web fornece duas maneiras de configurar aplicativos daemon:

Melhor para: Protótipos rápidos, aplicativos de console, testes e serviços daemon simples.

O código a seguir cria um TokenAcquirerFactory, configura APIs downstream e Microsoft Graph e chama o API do Graph:

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

Vantagens:

  • Código clichê mínimo
  • Carrega automaticamente appsettings.json
  • Perfeito para cenários simples
  • Inicialização em uma linha

Desvantagens:

  • Não adequado para testes executados em paralelo (singleton)

Melhor para: Aplicativos de produção, cenários complexos, injeção de dependência, testabilidade.

O código a seguir usa o host genérico .NET para configurar a autenticação, a aquisição de token, o cache e um serviço em segundo plano:

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

Vantagens:

  • Controle total sobre provedores de configuração
  • Melhor testabilidade com injeção de construtor
  • Integra-se ao modelo de hospedagem ASP.NET Core
  • Dá suporte a cenários complexos (vários esquemas de autenticação)
  • Arquitetura pronta para produção
  • Dá suporte à execução de teste paralelo (provedor de serviço isolado por teste)

Observação

O parâmetro true no AddTokenAcquisition(true) significa que o serviço é registrado como um singleton (instância única para o tempo de vida do aplicativo). Use false para o tempo de vida com escopo em aplicativos Web.

Recomendação: Comece com TokenAcquirerFactory protótipos e testes de thread único. Migre para o padrão completo ServiceCollection ao criar aplicativos de produção ou executar testes paralelos.


Configurar aplicativos daemon padrão

Os aplicativos daemon padrão são autenticados usando credenciais de cliente (segredo do cliente ou certificado) e obtêm tokens de acesso somente aplicativo para chamar APIs.

Definir configurações de autenticação

Adicione a configuração a seguir ao arquivo appsettings.json . Você pode usar um segredo do cliente ou um certificado (recomendado para produção):

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

Importante: Configure seu appsettings.json para copiar para o diretório de saída. Adicione o seguinte ao arquivo .csproj :

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

ASP.NET Core aplicativos copiam esse arquivo automaticamente, mas aplicativos daemon (e aplicativos OWIN) não.

Definir a configuração do serviço

O código Program.cs a seguir registra opções de identidade da Microsoft, aquisição de token, cache e um serviço hospedado em segundo plano:

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

Chamar Microsoft Graph

A seguinte classe DaemonWorker.cs usa o SDK do Graph para listar usuários em um agendamento recorrente:

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

Usar IAuthorizationHeaderProvider

Para obter mais controle sobre chamadas HTTP, use IAuthorizationHeaderProvider para criar cabeçalhos de autorização manualmente:

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

Consulte também Chamando APIs downstream para saber mais sobre todas as maneiras que o Microsoft Identity Web propõe chamar APIs downstream.


Configurar agentes autônomos (identidade do agente)

Agentes autônomos utilizam identidades de agentes para adquirir tokens de uso exclusivo para aplicativos. Esse padrão é útil para cenários Copilot e serviços autônomos.

Observação

Microsoft recomenda que os agentes que chamam APIs downstream façam isso de dentro de APIs Web protegidas, mesmo quando os agentes adquirem um token de aplicativo.

Configurar serviços de agente

O código a seguir configura a autenticação, a aquisição de tokens e o suporte à identidade do agente usando a configuração na memória:

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

Adquirir tokens com a identidade do agente

Depois de configurar os serviços do agente, adquira tokens usando IAuthorizationHeaderProvider ou o SDK do 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);
    });
});

Examinar um exemplo de agente autônomo completo

A classe a seguir encapsula a aquisição do token de identidade do agente e as chamadas à API do Graph em um serviço reutilizável.

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

Configurar a identidade do usuário do agente

A identidade do usuário do agente permite que os agentes atuem em nome de um usuário agente com permissões delegadas. Use esse padrão para agentes que precisam de sua própria caixa de correio ou outros recursos com escopo de usuário.

Pré-requisitos

Para usar a identidade do usuário do agente, você precisa:

  • Modelo do agente registrado no Microsoft Entra ID
  • Identidade do agente criada e vinculada ao aplicativo do agente
  • Identidade do usuário do agente associada à identidade do agente

Configurar serviços de usuário do agente

O código a seguir configura a identidade do aplicativo do agente com uma credencial de certificado e registra os serviços necessários:

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

Adquirir tokens de usuário com a identidade do agente

Você pode identificar o usuário de destino por UPN ou ID de objeto.

Por nome de usuário (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));
});

Por ID de objeto do usuário

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

Armazenar tokens em cache com ClaimsPrincipal

Para obter um melhor desempenho, armazene tokens de usuário em cache passando uma instância de ClaimsPrincipal. A primeira chamada popula o principal com as declarações uid e utid; chamadas subsequentes reutilizam o token em 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

Substituir o locatário

Para cenários multilocatários, você pode substituir o locatário em tempo de execução. Isso é útil quando o aplicativo está configurado com "common", mas precisa direcionar uma instância específica.

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

Examinar um exemplo completo de identidade de usuário de agente

A classe a seguir fornece métodos para obter perfis de usuário e cabeçalhos de autorização usando a identidade do usuário do agente:

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

Criar configuração de serviço reutilizável

Definir um método de extensão

Crie um método de extensão reutilizável para encapsular a configuração de identidade do agente em seu aplicativo:

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

Usar o método de extensão

Chame o método de extensão para configurar serviços em uma única linha:

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

var serviceProvider = services.ConfigureServicesForAgentIdentities(configuration);

APIs de chamada

Esta seção mostra como chamar APIs usando cada um dos três padrões de autenticação.

Chamar Microsoft Graph

Os exemplos a seguir demonstram chamar Microsoft Graph como um daemon padrão, um agente autônomo e uma identidade de usuário do agente:

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

Chamar APIs personalizadas com IDownstreamApi

Use IDownstreamApi para chamar suas próprias APIs protegidas com qualquer um dos três padrões de autenticação:

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

Fazer chamadas HTTP manuais

Use IAuthorizationHeaderProvider diretamente quando precisar de controle total sobre solicitações 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);

Configurar o cache de token

Escolha uma estratégia de cache com base em seu ambiente.

Desenvolvimento: cache na memória

Use o cache na memória para desenvolvimento e teste local:

services.AddInMemoryTokenCaches();

Produção: Cache distribuído

Para produção, use um cache distribuído para persistir tokens entre reinicializações de aplicativo e instâncias de expansão.

SQL Server

Armazene tokens em uma tabela de SQL Server:

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

Redis

Use o Redis para cache de token distribuído de alto desempenho:

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

Cosmos DB

Use o Cosmos DB para cache de token distribuído globalmente:

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

Saiba mais:Configuraçãodo cache de token


Explorar exemplos de Azure

Microsoft fornece exemplos que demonstram padrões de aplicativo daemon.

Repositório de exemplo

active-directory-dotnetcore-daemon-v2

Esse repositório contém vários cenários:

Amostra Descrição Link
1-Call-MSGraph Daemon básico chamando Microsoft Graph com credenciais de cliente Visualizar Exemplo
2-Call-OwnApi Daemon chamando sua própria API Web protegida Visualizar Exemplo
3-Using-KeyVault Daemon usando Azure Key Vault para armazenamento de certificados Visualizar Exemplo
4-Multi-inquilino Aplicativo daemon multilocatário Visualizar Exemplo
5-Call-MSGraph-ManagedIdentity Daemon usando Identidade Gerenciada no Azure Visualizar Exemplo

Comparar padrões de exemplo com padrões de produção

Os exemplos de Azure usam TokenAcquirerFactory.GetDefaultInstance() para simplificar – a abordagem recomendada para aplicativos de console simples, protótipos e testes. Este guia mostra os dois padrões:

Padrão TokenAcquirerFactory (Exemplos do Azure):

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

Padrão Full ServiceCollection (Aplicativos de Produção):

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

Quando usar qual:

  • Usar TokenAcquirerFactory para: Aplicativos de console, protótipos rápidos, testes de unidade, serviços daemon simples
  • Use ServiceCollection for: aplicativos de produção, integração ASP.NET Core, cenários de DI complexos, serviços em segundo plano com IHostedService

Ambas as abordagens têm suporte total e estão prontas para produção. Escolha com base nas necessidades de complexidade e integração do aplicativo.


Solucionar erros comuns

AADSTS700016: Aplicativo não encontrado

Causa: Inválido ClientId ou aplicativo não registrado no locatário.

Solution: Verifique se o ClientId em sua configuração corresponde ao registro do aplicativo Microsoft Entra.

Código de erro AADSTS7000215: chave secreta do cliente inválida

Causa: O segredo do cliente está incorreto, expirou ou não está configurado.

Solution:

  • Verifique se o segredo no portal Azure corresponde à sua configuração
  • Verificar a data de validade do segredo
  • Considere usar certificados para produção

AADSTS700027: a asserção do cliente contém assinatura inválida

Causa: Certificado não encontrado, expirado ou chave privada não acessível.

Solution:

  • Verificar se o certificado está instalado no repositório de certificados correto
  • Verificar se o nome distinto do certificado corresponde à configuração
  • Verifique se o aplicativo tem permissão para ler a chave privada
  • Consulte o Guia de Configuração de Certificado

AADSTS650052: O aplicativo precisa de acesso a um serviço

Causa: Permissões de API necessárias não concedidas ou consentimento do administrador ausentes.

Solution:

  1. Navegue até o portal Azure → Registros de aplicativo → Seu aplicativo → Permissões de API
  2. Adicionar permissões necessárias (por exemplo, User.Read.All para Microsoft Graph)
  3. Clique no botão "Conceder consentimento do administrador"

Erros de identidade do agente

AADSTS50105: O usuário conectado não está atribuído a uma função

Causa: Identidade do agente não configurada corretamente ou não atribuída ao aplicativo.

Solution:

  • Verifique se a identidade do agente existe no Microsoft Entra ID
  • Verifique se a identidade do agente está vinculada ao seu aplicativo
  • Verifique se a identidade do agente tem permissões necessárias

Tokens adquiridos, mas com permissões incorretas

Causa: Usando a identidade do usuário do agente, mas solicitando permissões de aplicativo ou vice-versa.

Solution:

  • Para tokens somente de aplicativo: use CreateAuthorizationHeaderForAppAsync com WithAgentIdentity
  • Para tokens delegados: use CreateAuthorizationHeaderForUserAsync com WithAgentUserIdentity
  • Verifique se as permissões de API correspondem ao tipo de token (aplicativo versus delegado)

Problemas de cache de token

Problema: Os tokens não são armazenados em cache, o que força uma nova aquisição a cada vez.

Solution:

  • Para a identidade do usuário do agente: reutilize a mesma ClaimsPrincipal instância entre chamadas
  • Verificar a conexão de cache distribuído (se estiver usando o Redis/SQL)
  • Habilitar o registro em log de depuração para ver as operações de cache

Diagnósticos detalhados:Guia de Registro em Log e Diagnóstico