Constrói aplicações de daemons e identidades de agentes com a Microsoft. Identity.Web

Neste artigo, construirás processos em segundo plano, serviços em segundo plano e agentes autónomos usando o Microsoft.Identity.Web. Estas aplicações funcionam sem interação do utilizador e autenticam-se usando a identidade da aplicação (credenciais do cliente) ou as identidades dos agentes.

Compreender cenários suportados

Microsoft. O Identity.Web suporta três tipos de aplicações não interativas:

Cenário Tipo de Autenticação Tipo de Token Caso de uso
Daemon Padrão Credenciais do cliente (secreto/certificado) Token de acesso apenas para aplicação Serviços de segundo plano, trabalhos agendados, processamento de dados
Agente Autónomo Identidade do agente com credenciais do cliente Token de acesso apenas para aplicação para agente Agentes Copilot, serviços autónomos que atuam em nome da identidade de um Agente. (Normalmente numa API Web protegida)
Identidade do Utilizador do Agente Identidade do utilizador do agente Identidade de utilizador do agente com as credenciais de cliente Serviços autónomos que atuam em nome da identidade de um utilizador agente. (Normalmente numa API Web protegida)

Introdução

Pré-requisitos

Antes de começar, certifique-se de que tem:

  • .NET 8.0 ou posterior
  • Microsoft Entra registo de aplicação com credenciais do cliente (secreto do cliente ou certificado)
  • Para cenários de agente: Identidades de agentes configuradas no seu tenant 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

Escolha uma abordagem de configuração

Microsoft. O Identity.Web oferece duas formas de configurar aplicações de daemons:

Melhor para: Protótipos rápidos, aplicações de consola, testes e serviços simples de daemons.

O seguinte código cria um TokenAcquirerFactory, configura APIs subsequentes e o Microsoft Graph, e chama a API do Microsoft 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 padrão mínimo
  • Carrega automaticamente appsettings.json
  • Perfeito para cenários simples
  • Inicialização numa única linha

Desvantagens:

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

Melhor para: Aplicações em produção, cenários complexos, injeção de dependências, teabilidade.

O seguinte código utiliza o Host Genérico .NET para configurar autenticação, aquisição de tokens, 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:

  • Controlo total sobre os fornecedores de configuração
  • Melhor testabilidade com injeção de construtor
  • Integra com o modelo de alojamento ASP.NET Core
  • Suporta cenários complexos (múltiplos esquemas de autenticação)
  • Arquitetura pronta para produção
  • Suporta execução de testes paralelos (fornecedor de serviço isolado por teste)

Observação

O parâmetro true em AddTokenAcquisition(true) significa que o serviço está registado como singleton (uma única instância durante a vida útil da aplicação). Use false para tempo de vida delimitado em aplicações web.

Recomendação: Comece com TokenAcquirerFactory para protótipos e testes monothread. Migre para o padrão completo ServiceCollection ao construir aplicações de produção ou executar testes paralelos.


Configurar aplicações padrão de daemons

As aplicações padrão de daemons autenticam-se usando credenciais de cliente (secreto do cliente ou certificado) e obtêm tokens de acesso exclusivos da aplicação para chamar APIs.

Configurar definições de autenticação

Adicione a seguinte configuração ao seu ficheiro deappsettings.json . Pode usar um segredo de 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: Defina o appsettings.json para copiar para o diretório de saída. Adicione o seguinte ao seu .csproj ficheiro:

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

As aplicações ASP.NET Core copiam este ficheiro automaticamente, mas as aplicações daemon (e as aplicações OWIN) não.

Configurar a configuração do serviço

O seguinte código Program.cs regista as opções de Identidade da Microsoft, a aquisição de tokens, o armazenamento em cache e um serviço em segundo plano hospedado:

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

Faça uma chamada ao Microsoft Graph

A seguinte DaemonWorker.cs classe utiliza o Graph SDK para listar utilizadores num calendário 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);
        }
    }
}

Utilize IAuthorizationHeaderProvider

Para maior controlo sobre chamadas HTTP, use IAuthorizationHeaderProvider para criar manualmente cabeçalhos de autorização:

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 Calling downstream APIs para saber todas as formas Microsoft Identity Web propõe chamar as downstream APIs.


Configurar agentes autónomos (identidade do agente)

Agentes autónomos usam identidades de agentes para obter tokens apenas para aplicações. Este padrão é útil para cenários Copilot e serviços autónomos.

Observação

A Microsoft recomenda que os agentes que chamam APIs downstream o façam a partir de APIs web protegidas, mesmo quando os agentes adquirem um token de aplicação.

Configurar serviços de agente

O seguinte código configura autenticação, aquisição de tokens e suporte à identidade do agente usando configuração em 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 de agente

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

Revise um exemplo completo de agente autónomo

A seguinte classe integra a aquisição de token de identidade de agente e as chamadas Graph API num 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 utilizador do agente

A identidade do utilizador do agente permite que os agentes atuem em nome de um utilizador do agente com permissões delegadas. Use este padrão para agentes que necessitem da sua própria caixa de correio ou de outros recursos com âmbito de utilizador.

Pré-requisitos

Para usar a identidade do utilizador agente, precisa de:

  • "Blueprint de agente registado no Microsoft Entra ID"
  • Identidade do agente criada e ligada à aplicação do agente
  • Identidade do utilizador do agente associada à identidade do agente

Configurar serviços de utilizador agente

O seguinte código configura a identidade da aplicação do agente com uma credencial de certificado e regista 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 identidade de agente

Pode identificar o utilizador-alvo pelo UPN ou pelo ID do objeto.

Por nome de utilizador (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 utilizador

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

Cache de tokens com "ClaimsPrincipal"

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

Anular o inquilino

Para cenários multi-inquilino, podes sobrepor o tenant em tempo de execução. Isto é útil quando a aplicação está configurada com "common", mas precisa direcionar um inquilino específico.

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

Revise um exemplo completo de identidade de utilizador de agente

A seguinte classe fornece métodos para obter perfis de utilizador e cabeçalhos de autorização usando a identidade do utilizador 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

Defina um método de extensão

Crie um método de extensão reutilizável para encapsular a configuração da identidade do agente em toda a sua aplicação:

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

Utilizar o método de extensão

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

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

var serviceProvider = services.ConfigureServicesForAgentIdentities(configuration);

APIs de chamadas

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

Faça uma chamada ao Microsoft Graph

Os exemplos seguintes demonstram como chamar o Microsoft Graph como um daemon padrão, um agente autónomo e uma identidade de utilizador 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"));
});

Invocar APIs personalizadas com IDownstreamApi

Use IDownstreamApi para chamar as 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");
    });

Faça chamadas HTTP manuais

Use IAuthorizationHeaderProvider diretamente quando precisar de controlo total sobre os pedidos 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 cache de tokens

Escolha uma estratégia de cache baseada no seu ambiente.

Desenvolvimento: Cache em memória

Use cache em memória para desenvolvimento e testes locais:

services.AddInMemoryTokenCaches();

Produção: Cache distribuída

Para produção, use uma cache distribuída para persistir tokens através de reinicios de aplicações e instâncias de scale-out.

SQL Server

Armazene tokens numa tabela 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 tokens distribuídos e de alto desempenho:

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

Cosmos DB

Utilize o Cosmos DB para caching global distribuído de tokens.

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

Saiba mais:Configuração da Cache do Token


Explore exemplos do Azure

A Microsoft fornece exemplos que demonstram padrões de aplicações daemon.

Repositório de exemplo

active-directory-dotnetcore-daemon-v2

Este repositório contém múltiplos cenários:

Exemplo Descrição Link
1-Call-MSGraph Daemon básico que chama o Microsoft Graph com credenciais do cliente Ver Exemplo
2-Call-OwnApi Daemon que chama a sua própria API web protegida Ver Exemplo
3-Using-KeyVault Daemon que utiliza o Azure Key Vault para armazenamento de certificados Ver Exemplo
4-Multi-Inquilino Aplicação de daemon multiusuário Ver Exemplo
5-Call-MSGraph-Managed Identity Daemon usando Identidade Gerida no Azure Ver Exemplo

Compare padrões de amostra com padrões de produção

Os Azure exemplos usam TokenAcquirerFactory.GetDefaultInstance() para simplificar — a abordagem recomendada para aplicações simples de consola, protótipos e testes. Este guia mostra ambos os padrões:

Padrão da Fábrica de Aquisição de Tokens (Amostras do Azure):

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

Padrão Full ServiceCollection (Aplicações 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:

  • Utilização TokenAcquirerFactory para: Aplicações de consola, protótipos rápidos, testes unitários, serviços simples de demónios
  • Use ServiceCollection para: aplicações de produção, integração ASP.NET Core, cenários complexos de DI, serviços em segundo plano com IHostedService

Ambas as abordagens são totalmente suportadas e prontas para produção. Escolha com base na complexidade e nas necessidades de integração da sua aplicação.


Solucionar erros comuns

AADSTS700016: Aplicação não encontrada

Causa: Inválido ClientId ou aplicação não registada no locatário.

Solução: Verifique se o ClientId na sua configuração corresponde ao registo da sua Microsoft Entra app.

AADSTS7000215: Segredo inválido do cliente

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

Solution:

  • Verifique se o segredo no portal do Azure corresponde à sua configuração
  • Verifique a data de expiração secreta
  • 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 que o certificado está instalado no armazenamento correto de certificados
  • Verificar se o nome distinto do certificado corresponde à configuração
  • Garantir que a aplicação tem permissão para ler a chave privada
  • Consulte o Guia de Configuração de Certificados

AADSTS650052: A aplicação precisa de acesso a um serviço

Causa: Permissões necessárias da API não concedidas ou consentimento do administrador em falta.

Solution:

  1. Navegue até o Portal Azure → Registo de Aplicações → A sua aplicação → Permissões da 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 utilizador com sessão iniciada não tem um papel atribuído

Causa: Identidade do agente não devidamente configurada ou não atribuída à aplicação.

Solution:

  • Verificar a existência da identidade do agente no Microsoft Entra ID
  • Assegure que a identidade do agente está associada à sua candidatura
  • Verifique se a identidade do agente tem permissões necessárias

Tokens adquiridos mas com permissões erradas

Causa: Usar a identidade do utilizador do agente mas pedir permissões para a aplicação, ou vice-versa.

Solution:

  • Para tokens apenas para aplicações: Usar CreateAuthorizationHeaderForAppAsync com WithAgentIdentity
  • Para tokens delegados: Usar CreateAuthorizationHeaderForUserAsync com WithAgentUserIdentity
  • Garantir que as permissões da API correspondem ao tipo de token (aplicação vs. delegado)

Problemas de cache de tokens

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

Solution:

  • Para a identidade do utilizador agente: Reutilizar a mesma ClaimsPrincipal instância entre chamadas
  • Verificar a ligação à cache distribuída (se estiver a usar Redis/SQL)
  • Habilitar a depuração de logs para ver as operações de cache

Diagnóstico detalhado:Guia de Registo e Diagnóstico