Per configurare il codice per l'API Web protetta, comprendere:
Cosa definisce le API come protette.
Come configurare un token di connessione.
Come convalidare il token.
Cosa definisce le API di ASP.NET e ASP.NET Core come protette?
Come le app Web, le API Web di ASP.NET e ASP.NET Core sono protette perché le azioni del controller sono precedute dall'attributo [Authorize]. Le azioni del controller possono essere chiamate solo se l'API viene chiamata con un'identità autorizzata.
Prendere in considerazione le domande seguenti:
Solo un'app può chiamare un'API Web. In che modo l'API conosce l'identità dell'app che la chiama?
Se l'app chiama l'API per conto di un utente, qual è l'identità dell'utente?
Token di connessione
Il token di connessione impostato nell'intestazione quando l'app viene chiamata contiene informazioni sull'identità dell'app. Contiene anche informazioni sull'utente, a meno che l'app Web non accetti chiamate da servizio a servizio da un'app daemon.
Ecco un esempio di codice C# che mostra un client che chiama l'API dopo aver acquisito un token con Microsoft Authentication Library per .NET (MSAL.NET):
var scopes = new[] {$"api://.../access_as_user"};
var result = await app.AcquireToken(scopes)
.ExecuteAsync();
httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
// Call the web API.
HttpResponseMessage response = await _httpClient.GetAsync(apiUri);
Importante
Un'applicazione client richiede il token di connessione Microsoft Identity Platform per l’API Web. L'API è l'unica applicazione che deve verificare il token e visualizzare le attestazioni contenute. Le app client non devono mai provare a esaminare le attestazioni nei token.
In futuro, l'API Web potrebbe richiedere che il token sia crittografato. Questo requisito impedisce l'accesso alle app client in grado di visualizzare i token di accesso.
Configurazione di JwtBearer
In questa sezione viene descritto come configurare un token di connessione.
File di configurazione
È necessario specificare il TenantId solo se si desidera accettare i token di accesso da un singolo tenant (applicazione line-of-business). In caso contrario, può essere lasciato come common. I diversi valori possono essere:
Un GUID (ID tenant = ID directory)
common può essere qualsiasi organizzazione e account personale
Uso di un URI ID app personalizzato per un'API Web
Se è stato accettato l'URI ID app predefinito proposto dal portale di Azure, non è necessario specificare il gruppo di destinatari (vedere URI ID applicazione e ambiti). In caso contrario, aggiungere una proprietà Audience il cui valore è l'URI ID app per l'API Web. In genere inizia con api://.
Quando un'app viene chiamata su un'azione controller che contiene un attributo [Authorize], ASP.NET e ASP.NET Core estraggono il token di accesso dal token di connessione dell'intestazione di autorizzazione. Il token di accesso viene quindi inoltrato al middleware JwtBearer, che chiama le estensioni Microsoft IdentityModel per .NET.
Microsoft consiglia di usare il pacchetto NuGet Microsoft.Identity.Web durante lo sviluppo di un'API Web con ASP.NET Core.
Microsoft.Identity.Web fornisce l'associazione tra ASP.NET Core, il middleware di autenticazione e Microsoft Authentication Library (MSAL) per .NET. Consente un'esperienza di sviluppo più chiara e affidabile e sfrutta la potenza di Microsoft Identity Platform e Azure AD B2C.
ASP.NET per NET 6.0
Per creare un nuovo progetto API Web che usa Microsoft.Identity.Web, usare un modello di progetto nell'interfaccia della riga di comando di .NET 6.0 o in Visual Studio.
Interfaccia della riga di comando di Dotnet
# Create new web API that uses Microsoft.Identity.Web
dotnet new webapi --auth SingleOrg
Visual Studio: per creare un progetto API Web in Visual Studio, selezionare File>Nuovo>Progetto>ASP.NET Core.
Sia l'interfaccia della riga di comando di .NET che i modelli di progetto di Visual Studio creano un file Program.cs simile a questo frammento di codice. Si noti come Microsoft.Identity.Web utilizza la direttiva e le righe contenenti l'autenticazione e l'autorizzazione.
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Identity.Web;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd"));
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();
Microsoft consiglia di usare il pacchetto NuGet Microsoft.Identity.Web.OWIN durante lo sviluppo di un'API Web con ASP.NET.
Microsoft.Identity.Web.OWIN fornisce l'associazione tra ASP.NET, il middleware di autenticazione ASP.NET e Microsoft Authentication Library (MSAL) per .NET. Consente un'esperienza di sviluppo più chiara e affidabile e sfrutta la potenza di Microsoft Identity Platform e Azure AD B2C.
Usa lo stesso file di configurazione di ASP.NET Core (appsettings.json) ed è necessario assicurarsi che questo file venga copiato con l'output del progetto (copia delle proprietà sempre nelle proprietà del file in Visual Studio o nel file con estensione .csproj)
Microsoft.Identity.Web.OWIN aggiunge un metodo di estensione a IAppBuilder denominato AddMicrosoftIdentityWebApi. Questo metodo accetta come parametro un'istanza di OwinTokenAcquirerFactory che si ottiene chiamando OwinTokenAcquirerFactory.GetDefaultInstance<OwinTokenAcquirerFactory>() e che espone un'istanza di IServiceCollection a cui è possibile aggiungere molti servizi per chiamare le API downstream o configurare la cache dei token.
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.Cookies;
using Owin;
using Microsoft.Identity.Web;
using Microsoft.Identity.Web.TokenCacheProviders.InMemory;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Identity.Client;
using Microsoft.Identity.Abstractions;
using Microsoft.Identity.Web.OWIN;
using System.Web.Services.Description;
namespace OwinWebApp
{
public partial class Startup
{
public void ConfigureAuth(IAppBuilder app)
{
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions());
OwinTokenAcquirerFactory factory = TokenAcquirerFactory.GetDefaultInstance<OwinTokenAcquirerFactory>();
app.AddMicrosoftIdentityWebApp(factory);
factory.Services
.Configure<ConfidentialClientApplicationOptions>(options => { options.RedirectUri = "https://localhost:44386/"; })
.AddMicrosoftGraph()
.AddDownstreamApi("DownstreamAPI1", factory.Configuration.GetSection("DownstreamAPI"))
.AddInMemoryTokenCaches();
factory.Build();
}
}
}
--
Convalida dei token
Nel frammento di codice precedente, il middleware JwtBearer, ad esempio il middleware OpenID Connect nelle app Web, convalida il token in base al valore di TokenValidationParameters. Il token viene decrittografato in base alle esigenze, le attestazioni vengono estratte e la firma viene verificata. Il middleware convalida quindi il token controllando i dati seguenti:
Destinatari: il token è destinato all'API Web.
Sub: è stato rilasciato per un'app autorizzata a chiamare l'API Web.
Autorità di certificazione: è stata emessa da un servizio token di sicurezza attendibile.
Scadenza: la durata è compresa nell'intervallo.
Firma: non è stata manomessa.
Possono essere presenti anche convalide speciali. Ad esempio, è possibile verificare che le chiavi di firma, incorporate in un token, siano attendibili e che il token non venga riprodotto. Infine, alcuni protocolli richiedono convalide specifiche.
Nella tabella seguente vengono descritti i validatori:
Validator
Descrizione
ValidateAudience
Garantisce che il token sia per l'applicazione che convalida il token.
ValidateIssuer
Garantisce che il token sia stato emesso da un servizio token di sicurezza attendibile, ovvero da un utente attendibile.
ValidateIssuerSigningKey
Garantisce che l'applicazione che convalida il token consideri attendibile la chiave usata per firmare il token. Esiste un caso speciale in cui la chiave è incorporata nel token. Ma questo caso di solito non si verifica.
ValidateLifetime
Garantisce che il token sia ancora o già valido. Il validatore controlla se la durata del token si trova all’interno dell'intervallo specificato dalle attestazioni notbefore ed expires.
ValidateSignature
Garantisce che il token non sia stato manomesso.
ValidateTokenReplay
Garantisce che il token non venga riprodotto. C'è un caso speciale per alcuni protocolli mono uso.
Personalizzazione della convalida dei token
I validator sono associati alle proprietà della classe TokenValidationParameters. Le proprietà vengono inizializzate dalla configurazione di ASP.NET e ASP.NET Core.
Nella maggior parte dei casi, non è necessario modificare i parametri. Le app che non sono tenant singoli fanno eccezione. Queste app Web accettano utenti di qualsiasi organizzazione o da account Microsoft personali. In questo caso, è necessario convalidare le autorità emettenti. Microsoft.Identity.Web si occupa anche della convalida dell'autorità emittente.
In ASP.NET Core, se si vogliono personalizzare i parametri di convalida del token, usare il frammento di codice seguente nel Startup.cs:
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApi(Configuration);
services.Configure<JwtBearerOptions>(JwtBearerDefaults.AuthenticationScheme, options =>
{
options.TokenValidationParameters.ValidAudiences = new[] { /* list of valid audiences */};
});
Per ASP.NET MVC, il seguente esempio di codice illustra come eseguire la convalida del token personalizzata:
È anche possibile convalidare i token di accesso in ingresso in Funzioni di Azure. È possibile trovare esempi di tale convalida negli esempi di codice seguenti in GitHub: