Chiamare gli SDK di Azure utilizzando MicrosoftIdentityTokenCredential

Usare MicrosoftIdentityTokenCredential da Microsoft.Identity.Web.Azure per autenticare i client di Azure SDK (Archiviazione, Key Vault, bus di servizio e altro ancora) con Microsoft Entra ID.

Informazioni su MicrosoftIdentityTokenCredential

La classe MicrosoftIdentityTokenCredential implementa l'interfaccia Azure SDK TokenCredential. Questa integrazione consente di usare la stessa configurazione di autenticazione e la stessa infrastruttura di memorizzazione nella cache dei token nell'intera applicazione.

Esaminare i vantaggi

MicrosoftIdentityTokenCredential offre i vantaggi seguenti:

  • Autenticazione unificata: usare la stessa configurazione di autenticazione per app Web, API e servizi Azure
  • Memorizzazione nella cache dei token: memorizzazione e aggiornamento automatici dei token
  • Autorizzazioni delegate e app: supporto per token utente e applicazione
  • Identità agente: funzionalità compatibile con le identità degli agenti
  • Managed Identity: integrazione facile con identità gestita Azure

Installare i pacchetti

Installare il pacchetto di integrazione Azure:

dotnet add package Microsoft.Identity.Web.Azure

Installare quindi i pacchetti client Azure SDK necessari:

# 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

Configurare ASP.NET Core

1. Configurare i servizi

Il codice seguente registra l'autenticazione e aggiunge il supporto delle credenziali del token di Azure all'applicazione.

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. Configurare appsettings.json

Aggiungere la configurazione Microsoft Entra al file appsettings.json:

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

Usare MicrosoftIdentityTokenCredential

Iniettare e utilizzare con i client dell'SDK di Azure

Nell'esempio seguente viene illustrato come inserire MicrosoftIdentityTokenCredential e usarlo con Archiviazione BLOB di Azure. Lo stesso approccio si applica a tutti i client Azure SDK.

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

Usare le autorizzazioni delegate

Chiamare i servizi di Azure per conto dell'utente autenticato usando autorizzazioni delegate.

Caricare file con Archiviazione di Azure

Il controller seguente illustra come caricare un file in Archiviazione BLOB di Azure usando un token delegato:

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

Usare le autorizzazioni dell'applicazione

Chiamare i servizi di Azure con autorizzazioni dell'applicazione quando non è disponibile alcun contesto utente.

Configurare i token per sole app

Impostare RequestAppToken su true nelle opzioni delle credenziali per acquisire un token esclusivo per l'app:

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

Creare un'applicazione daemon

L'esempio seguente illustra come compilare un'applicazione daemon autonoma che accede a Archiviazione BLOB di Azure con autorizzazioni solo app:

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

Integrare le identità dell'agente

MicrosoftIdentityTokenCredential supporta le identità dell'agente tramite la Options proprietà . La classe di servizio seguente illustra come configurare le identità di agenti e utenti-agente:

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

Per altri dettagli, vedere la documentazione relativa alle identità dell'agente .

Configurare FIC e Identità gestita

MicrosoftIdentityTokenCredential funziona con FIC e Azure Managed Identity.

Configurare le credenziali dell'identità gestita

Aggiungere la configurazione seguente per usare l'identità gestita come origine delle credenziali:

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

Usare l'identità gestita assegnata dal sistema

Quando si esegue la distribuzione in Azure, le credenziali usano automaticamente l'identità gestita assegnata dal sistema. La classe di servizio seguente illustra questo modello:

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

Usare l'identità gestita assegnata dall'utente

Specificare la configurazione ManagedIdentityClientId per usare un'identità gestita assegnata dall'utente:

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

Implementare l'autenticazione OWIN

Per ASP.NET applicazioni che usano OWIN, registrare le credenziali del token Azure nella classe di avvio:

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

Seguire le migliori pratiche

1. Riutilizzare Azure SDK client

Azure SDK sono client thread-safe, quindi risultano riutilizzabili tra le richieste. Tuttavia, MicrosoftIdentityTokenCredential è un servizio con ambito, quindi non è possibile usarlo con AddAzureServices(), che crea singleton.

2. Usare l'identità gestita nell'ambiente di produzione

Preferisce l'autenticazione senza certificati con identità gestita negli ambienti di produzione:

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

3. Gestione delle eccezioni di Azure SDK

Includere le chiamate Azure SDK in blocchi try-catch per gestire scenari di errore comuni.

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. Usare la configurazione per gli URI

Archiviare gli URI delle risorse Azure nella configurazione anziché hardcodificarli:

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

Risolvere gli errori comuni

Risolvere "ManagedIdentityCredential authentication failed" (Autenticazione managedIdentityCredential non riuscita)

Causa: l'identità gestita non è abilitata o non è configurata correttamente.

Soluzione:

  • Abilitare l'identità gestita nella risorsa Azure (servizio app, macchina virtuale e così via)
  • Per l'identità assegnata dall'utente, specificare ManagedIdentityClientId
  • Verificare che l'identità abbia le assegnazioni di ruolo necessarie

Risolvere "Questa richiesta non è autorizzata a eseguire questa operazione"

Cause: Mancante l'assegnazione del ruolo nel Controllo degli Accessi Basato sui Ruoli di Azure.

Soluzione:

  • Assegnare un ruolo appropriato all'identità gestita o all'utente
  • Esempio: "Contributore ai dati dei BLOB di archiviazione" per le operazioni sui BLOB
  • Attendere fino a 5 minuti per la propagazione delle assegnazioni di ruolo

Correggere gli errori di acquisizione dei token locali

Cause: l'identità gestita funziona solo in Azure.

Soluzione: usare origini credenziali diverse in locale:

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

Correggere gli errori di ambito con le risorse di Azure

Causa: formato di ambito non corretto.

Solution: Usare ambiti specifici della risorsa Azure:

  • Archiviazione: https://storage.azure.com/user_impersonation o .default
  • KeyVault: https://vault.azure.net/user_impersonation o .default
  • bus di servizio: https://servicebus.azure.net/user_impersonation o .default

Passaggi successivi: informazioni sulla chiamata di API personalizzate con IDownstreamApi e IAuthorizationHeaderProvider.