Chamar SDKs do Azure com MicrosoftIdentityTokenCredential

Use MicrosoftIdentityTokenCredential do Microsoft.Identity.Web.Azure para autenticar clientes do SDK do Azure (Armazenamento, Key Vault, Barramento de Serviço e muito mais) com o Microsoft Entra ID.

Entender MicrosoftIdentityTokenCredential

A classe MicrosoftIdentityTokenCredential implementa a interface SDK do Azure TokenCredential. Essa integração permite que você use a mesma configuração de autenticação e infraestrutura de cache de token em todo o aplicativo.

Examinar os benefícios

MicrosoftIdentityTokenCredential fornece as seguintes vantagens:

  • Unified Authentication: use a mesma configuração de autenticação para aplicativos Web, APIs e serviços de Azure
  • Cache de token: cache e atualização automáticos de token
  • Permissões delegadas e de aplicativo: suporte para tokens de usuário e aplicativo
  • Identidades do agente: compatível com o recurso de identidades do agente
  • Managed Identity: integração perfeita com Azure Identidade Gerenciada

Instalar os pacotes

Instale o pacote de integração Azure:

dotnet add package Microsoft.Identity.Web.Azure

Em seguida, instale os pacotes de cliente SDK do Azure necessários:

# Examples
dotnet add package Azure.Storage.Blobs
dotnet add package Azure.Security.KeyVault.Secrets
dotnet add package Azure.Messaging.ServiceBus
dotnet add package Azure.Data.Tables

Configurar ASP.NET Core

1. Configurar serviços

O código a seguir registra a autenticação e adiciona Azure suporte à credencial de token ao seu aplicativo:

using Microsoft.Identity.Web;

var builder = WebApplication.CreateBuilder(args);

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

// Add Azure token credential support
builder.Services.AddMicrosoftIdentityAzureTokenCredential();

builder.Services.AddControllersWithViews();

var app = builder.Build();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();

2. Configurar appsettings.json

Adicione a configuração de Microsoft Entra ao arquivo appsettings.json:

{
  "AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "TenantId": "your-tenant-id",
    "ClientId": "your-client-id",
    "ClientCredentials": [
      {
        "SourceType": "SignedAssertionFromManagedIdentity"
      }
    ]
  }
}

Usar MicrosoftIdentityTokenCredential

Injete e use com os clientes do SDK do Azure

O exemplo a seguir mostra como injetar MicrosoftIdentityTokenCredential e usá-lo com Armazenamento de Blobs do Azure. A mesma abordagem se aplica a todos os clientes SDK do Azure.

using Azure.Storage.Blobs;
using Microsoft.Identity.Web;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

[Authorize]
public class StorageController : Controller
{
    private readonly MicrosoftIdentityTokenCredential _credential;
    private readonly IConfiguration _configuration;
    
    public StorageController(
        MicrosoftIdentityTokenCredential credential,
        IConfiguration configuration)
    {
        _credential = credential;
        _configuration = configuration;
    }
    
    public async Task<IActionResult> ListBlobs()
    {
        // Create Azure SDK client with credential
        var blobClient = new BlobServiceClient(
            new Uri($"https://{_configuration["StorageAccountName"]}.blob.core.windows.net"),
            _credential);
        
        var container = blobClient.GetBlobContainerClient("mycontainer");
        var blobs = new List<string>();
        
        await foreach (var blob in container.GetBlobsAsync())
        {
            blobs.Add(blob.Name);
        }
        
        return View(blobs);
    }
}

Usar permissões delegadas

Utilize os serviços do Azure em nome do usuário autenticado usando permissões delegadas.

Carregar arquivos com Armazenamento do Azure

O controlador a seguir demonstra como carregar um arquivo para Armazenamento de Blobs do Azure usando um token delegado:

using Azure.Storage.Blobs;
using Microsoft.Identity.Web;

[Authorize]
public class FileController : Controller
{
    private readonly MicrosoftIdentityTokenCredential _credential;
    
    public FileController(MicrosoftIdentityTokenCredential credential)
    {
        _credential = credential;
    }
    
    public async Task<IActionResult> UploadFile(IFormFile file)
    {
        // Credential will automatically acquire delegated token
        var blobClient = new BlobServiceClient(
            new Uri("https://myaccount.blob.core.windows.net"),
            _credential);
        
        var container = blobClient.GetBlobContainerClient("uploads");
        await container.CreateIfNotExistsAsync();
        
        var blob = container.GetBlobClient(file.FileName);
        await blob.UploadAsync(file.OpenReadStream(), overwrite: true);
        
        return Ok($"File {file.FileName} uploaded");
    }
}

Usar permissões de aplicativo

Chame os serviços do Azure com permissões de aplicação quando não houver contexto de usuário disponível.

Configurar tokens somente de aplicativo

Defina RequestAppToken para true nas opções de credencial para adquirir um token somente de aplicativo.

public class AzureService
{
    private readonly MicrosoftIdentityTokenCredential _credential;
    
    public AzureService(MicrosoftIdentityTokenCredential credential)
    {
        _credential = credential;
    }
    
    public async Task<List<string>> ListBlobsAsync()
    {
        // Configure credential for app-only token
        _credential.Options.RequestAppToken = true;
        
        var blobClient = new BlobServiceClient(
            new Uri("https://myaccount.blob.core.windows.net"),
            _credential);
        
        var container = blobClient.GetBlobContainerClient("data");
        var blobs = new List<string>();
        
        await foreach (var blob in container.GetBlobsAsync())
        {
            blobs.Add(blob.Name);
        }
        
        return blobs;
    }
}

Criar um aplicativo daemon

O exemplo a seguir mostra como criar um aplicativo daemon autônomo que acessa Armazenamento de Blobs do Azure com permissões somente de aplicativo:

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Identity.Abstractions;
using Microsoft.Identity.Web;
using Azure.Storage.Blobs;

class Program
{
    static async Task Main(string[] args)
    {
        // Build service provider
        var tokenAcquirerFactory = TokenAcquirerFactory.GetDefaultInstance();
        tokenAcquirerFactory.Services.AddMicrosoftIdentityAzureTokenCredential();
        var sp = tokenAcquirerFactory.Build();
        
        // Get credential
        var credential = sp.GetRequiredService<MicrosoftIdentityTokenCredential>();
        credential.Options.RequestAppToken = true;
        
        // Use with Azure SDK
        var blobClient = new BlobServiceClient(
            new Uri("https://myaccount.blob.core.windows.net"),
            credential);
        
        var container = blobClient.GetBlobContainerClient("data");
        
        await foreach (var blob in container.GetBlobsAsync())
        {
            Console.WriteLine($"Blob: {blob.Name}");
        }
    }
}

Integrar identidades do agente

MicrosoftIdentityTokenCredential suporta identidades de agentes através da propriedade Options. A classe de serviço a seguir mostra como configurar identidades de agente e agente-usuário:

using Microsoft.Identity.Web;

public class AgentService
{
    private readonly MicrosoftIdentityTokenCredential _credential;
    
    public AgentService(MicrosoftIdentityTokenCredential credential)
    {
        _credential = credential;
    }
    
    public async Task<List<string>> ListBlobsForAgentAsync(string agentIdentity)
    {
        // Configure for agent identity
        _credential.Options.WithAgentIdentity(agentIdentity);
        _credential.Options.RequestAppToken = true;
        
        var blobClient = new BlobServiceClient(
            new Uri("https://myaccount.blob.core.windows.net"),
            _credential);
        
        var container = blobClient.GetBlobContainerClient("agent-data");
        var blobs = new List<string>();
        
        await foreach (var blob in container.GetBlobsAsync())
        {
            blobs.Add(blob.Name);
        }
        
        return blobs;
    }
    
    public async Task<string> GetSecretForAgentUserAsync(string agentIdentity, Guid userOid, string secretName)
    {
        // Configure for agent user identity
        _credential.Options.WithAgentUserIdentity(agentIdentity, userOid);
        
        var secretClient = new SecretClient(
            new Uri("https://myvault.vault.azure.net"),
            _credential);
        
        var secret = await secretClient.GetSecretAsync(secretName);
        return secret.Value.Value;
    }
}

Consulte a documentação de Identidades do Agente para obter mais detalhes.

Configurar o FIC e a Identidade Gerenciada

MicrosoftIdentityTokenCredential funciona com FIC e Azure Managed Identity.

Configurar credenciais de Identidade Gerenciada

Adicione a seguinte configuração para usar a Identidade Gerenciada como uma fonte de credencial:

{
  "AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "TenantId": "your-tenant-id",
    "ClientId": "your-client-id",
    "ClientCredentials": [
      {
        "SourceType": "SignedAssertionFromManagedIdentity"
      }
    ]
  }
}

Usar a Identidade Gerenciada atribuída pelo sistema

Quando você implanta em Azure, a credencial usa automaticamente a identidade gerenciada atribuída pelo sistema. A seguinte classe de serviço demonstra esse padrão:

// No additional code needed!
// When deployed to Azure, the credential automatically uses managed identity

public class StorageService
{
    private readonly MicrosoftIdentityTokenCredential _credential;
    
    public StorageService(MicrosoftIdentityTokenCredential credential)
    {
        _credential = credential;
        _credential.Options.RequestAppToken = true;
    }
    
    public async Task<List<string>> ListContainersAsync()
    {
        // Uses managed identity when running in Azure
        var blobClient = new BlobServiceClient(
            new Uri("https://myaccount.blob.core.windows.net"),
            _credential);
        
        var containers = new List<string>();
        await foreach (var container in blobClient.GetBlobContainersAsync())
        {
            containers.Add(container.Name);
        }
        
        return containers;
    }
}

Usar a Identidade Gerenciada atribuída pelo usuário

Especifique o ManagedIdentityClientId na sua configuração para usar uma identidade gerenciada atribuída pelo usuário:

{
  "AzureAd": {
    "ClientCredentials": [
      {
        "SourceType": "SignedAssertionFromManagedIdentity",
        "ManagedIdentityClientId": "user-assigned-identity-client-id"
      }
    ]
  }
}

Implementar a autenticação OWIN

Para aplicativos ASP.NET que usam OWIN, registre a credencial de token Azure na classe de inicialização:

using Microsoft.Identity.Web;
using Microsoft.Identity.Web.OWIN;
using Owin;

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
     app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
     app.UseCookieAuthentication(new CookieAuthenticationOptions());

     OwinTokenAcquirerFactory factory = TokenAcquirerFactory.GetDefaultInstance<OwinTokenAcquirerFactory>();

     app.AddMicrosoftIdentityWebApp(factory);
     factory.Services
        .AddMicrosoftIdentityAzureTokenCredential();
      factory.Build();
    }
}

Seguir as práticas recomendadas

1. Reutilizar clientes SDK do Azure

SDK do Azure clientes são thread-safe, portanto, reutilize-os entre solicitações. No entanto, MicrosoftIdentityTokenCredential é um serviço com escopo, portanto, você não pode usá-lo com AddAzureServices(), o que cria singletons.

2. Usar Identidade Gerenciada em produção

Prefira a autenticação sem certificado com identidade gerenciada em ambientes de produção:

//  Good: Certificateless auth with managed identity
{
  "ClientCredentials": [
    {
      "SourceType": "SignedAssertionFromManagedIdentity"
    }
  ]
}

3. Manipular exceções de SDK do Azure

Envolva as chamadas do SDK do Azure em blocos try-catch para tratar cenários comuns de falha.

using Azure;

try
{
    var blob = await blobClient.DownloadAsync();
}
catch (RequestFailedException ex) when (ex.Status == 404)
{
    // Blob not found
}
catch (RequestFailedException ex) when (ex.Status == 403)
{
    // Insufficient permissions
}
catch (RequestFailedException ex)
{
    _logger.LogError(ex, "Azure SDK call failed with status {Status}", ex.Status);
}

5. Usar a configuração para URIs

Armazenar URIs de recursos do Azure em configurações, em vez de inseri-los diretamente no código.

//  Bad: Hardcoded URIs
var blobClient = new BlobServiceClient(new Uri("https://myaccount.blob.core.windows.net"), credential);

//  Good: Configuration-driven
var storageUri = _configuration["Azure:Storage:Uri"];
var blobClient = new BlobServiceClient(new Uri(storageUri), credential);

Solucionar erros comuns

Solucionar "Falha na autenticação da ManagedIdentityCredential"

Causa: identidade gerenciada não habilitada ou configurada incorretamente.

Solução:

  • Habilitar a identidade gerenciada no recurso Azure (Serviço de Aplicativo, VM etc.)
  • Para a identidade atribuída pelo usuário, especifique ManagedIdentityClientId
  • Verificar se a identidade tem atribuições de função necessárias

Resolver "Esta solicitação não está autorizada a executar esta operação"

Cause: Ausência de atribuição de função do RBAC do Azure.

Solução:

  • Atribuir a função apropriada à identidade gerenciada ou ao usuário
  • Exemplo: "Colaborador de Dados de Armazenamento Blob" para operações de blob
  • Aguarde até 5 minutos para que as atribuições de função sejam propagadas

Corrigir falhas de aquisição de token local

Cause: a identidade gerenciada funciona apenas em Azure.

Solução: use uma fonte de credencial diferente localmente:

{
  "ClientCredentials": [
    {
      "SourceType": "ClientSecret",
      "ClientSecret": "secret-for-local-dev"
    }
  ]
}

Corrigir erros de escopo com recursos de Azure

Causa: formato de escopo incorreto.

Solution: Use escopos específicos de recursos do Azure:

  • Armazenamento: https://storage.azure.com/user_impersonation ou .default
  • KeyVault: https://vault.azure.net/user_impersonation ou .default
  • Barramento de Serviço: https://servicebus.azure.net/user_impersonation ou .default

Próximas etapas: saiba mais sobre como chamar APIs personalizadas com IDownstreamApi e IAuthorizationHeaderProvider.