Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Si applica a:
I tenant della forza lavoro
I tenant esterni (Altre informazioni)
Questa serie di esercitazioni illustra come proteggere un'API Web ASP.NET Core con Microsoft Identity Platform per limitare l'accesso solo agli utenti autorizzati e alle app client. L'API Web compilata usa autorizzazioni delegate (ambiti) e autorizzazioni dell'applicazione (ruoli dell'app).
In questa esercitazione, farai:
- Creare un'API Web ASP.NET Core
- Configurare l'API Web per utilizzare i dettagli di registrazione dell'app di Microsoft Entra
- Proteggere gli endpoint dell'API Web
- Eseguire l'API Web per assicurarsi che sia in ascolto delle richieste HTTP
Prerequisiti
- Se non è già stato fatto, completare la procedura descritta in Avvio rapido: Chiamare un'API Web protetta da Microsoft Identity Platform. Non è necessario clonare ed eseguire l'esempio di codice, ma assicurarsi di disporre degli elementi seguenti:
- I dettagli di registrazione dell'app dell'API Web dall'interfaccia di amministrazione di Microsoft Entra, inclusi l'ID client e l'ID tenant.
- ToDoList.Read e ToDoList.ReadWrite come autorizzazioni delegate (scopi) esposte dall'API Web
- ToDoList.Read.All e ToDoList.ReadWrite.All come autorizzazioni dell'applicazione (ruoli dell'app) esposte dall'API Web
- .NET 8.0 SDK o versione successiva.
- Visual Studio Code o un altro editor di codice.
Creare un nuovo progetto API Web di ASP.NET Core
Per creare un progetto API Web core ASP.NET minimo, seguire questa procedura:
Aprire il terminale in Visual Studio Code o in qualsiasi altro editor di codice e passare alla directory in cui si vuole creare il progetto.
Eseguire i comandi seguenti nell'interfaccia della riga di comando di .NET o in qualsiasi altro strumento da riga di comando.
dotnet new web -o TodoListApi cd TodoListApiSelezionare Sì quando una finestra di dialogo chiede se si vuole considerare attendibili gli autori.
Selezionare Sì Quando una finestra di dialogo chiede se si desidera aggiungere gli asset necessari al progetto.
Installare i pacchetti necessari
Per compilare, proteggere e testare l'API Web ASP.NET Core, è necessario installare i pacchetti seguenti:
-
Microsoft.EntityFrameworkCore.InMemory- Pacchetto che consente di usare Entity Framework Core con un database in memoria. È utile a scopo di test, ma non è progettato per l'uso in produzione. -
Microsoft.Identity.Web: un set di librerie core di ASP.NET che semplificano l'aggiunta del supporto di autenticazione e autorizzazione alle app Web e alle API Web che si integrano con Microsoft Identity Platform.
Per installare il pacchetto, usare:
dotnet add package Microsoft.EntityFrameworkCore.InMemory
dotnet add package Microsoft.Identity.Web
Configurare i dettagli di registrazione dell'app
Aprire il file appsettings.json nella cartella dell'app e aggiungere i dettagli di registrazione dell'app registrati dopo la registrazione dell'API Web.
{
"AzureAd": {
"Instance": "Enter_the_Authority_URL_Here",
"TenantId": "Enter_the_Tenant_Id_Here",
"ClientId": "Enter_the_Application_Id_Here"
},
"Logging": {...},
"AllowedHosts": "*"
}
Sostituire i segnaposto seguenti come illustrato:
- Sostituire
Enter_the_Application_Id_Herecon l'ID applicazione (client). - Sostituire
Enter_the_Tenant_Id_Herecon l'ID della directory (tenant). - Sostituire
Enter_the_Authority_URL_Herecon l'URL dell'autorità, come illustrato nella sezione successiva.
URL dell'autorità per l'app
L'URL dell'autorità specifica la directory da cui Microsoft Authentication Library (MSAL) può richiedere token. Lo costruisci in modo diverso sia nella forza lavoro che negli affittuari esterni, come illustrato di seguito.
//Instance for workforce tenant
Instance: "https://login.microsoftonline.com/"
Usare un dominio URL personalizzato (facoltativo)
I domini URL personalizzati non sono supportati nelle utenze aziendali.
Aggiungere autorizzazioni
Tutte le API devono pubblicare almeno un ambito, detto anche autorizzazione delegata, affinché le app client ottengano correttamente un token di accesso per un utente. Le API devono anche pubblicare almeno un ruolo dell'applicazione, detto anche autorizzazioni dell'applicazione, affinché le app client ottengano un token di accesso in qualità di sé stesse, ovvero quando non effettuano l'accesso come utente.
Queste autorizzazioni vengono specificate nel file appsettings.json. In questa esercitazione sono state registrate le seguenti autorizzazioni delegate e dell'applicazione:
- Autorizzazioni delegate:ToDoList.Read e ToDoList.ReadWrite.
- Autorizzazioni delle applicazioni:ToDoList.Read.All e ToDoList.ReadWrite.All.
Quando un utente o un'applicazione client chiama l'API Web, solo i client con questi ambiti o le autorizzazioni vengono autorizzati ad accedere all'endpoint protetto.
{
"AzureAd": {
"Instance": "Enter_the_Authority_URL_Here",
"TenantId": "Enter_the_Tenant_Id_Here",
"ClientId": "Enter_the_Application_Id_Here",
"Scopes": {
"Read": ["ToDoList.Read", "ToDoList.ReadWrite"],
"Write": ["ToDoList.ReadWrite"]
},
"AppPermissions": {
"Read": ["ToDoList.Read.All", "ToDoList.ReadWrite.All"],
"Write": ["ToDoList.ReadWrite.All"]
}
},
"Logging": {...},
"AllowedHosts": "*"
}
Implementare l'autenticazione e l'autorizzazione nell'API
Per configurare l'autenticazione e l'autorizzazione, aprire il file program.cs e sostituirne il contenuto nei frammenti di codice seguenti:
Aggiungere uno schema di autenticazione
In questa API viene usato lo schema di connessione JWT (JSON Web Token) come meccanismo di autenticazione predefinito. Usare il metodo AddAuthentication per registrare lo schema bearer JWT.
// Add required packages to your imports
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Identity.Web;
var builder = WebApplication.CreateBuilder(args);
// Add an authentication scheme
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApi(builder.Configuration);
Creare il modello dell'app
Nella cartella radice del progetto creare una cartella denominata Models. Passare alla cartella Models e creare un file denominato ToDo.cs e quindi aggiungere il codice seguente.
using System;
namespace ToDoListAPI.Models;
public class ToDo
{
public int Id { get; set; }
public Guid Owner { get; set; }
public string Description { get; set; } = string.Empty;
}
Il codice precedente crea un modello denominato ToDo. Questo modello rappresenta i dati gestiti dall'app.
Aggiungere un contesto di database
Verrà quindi definita una classe di contesto del database, che coordina la funzionalità di Entity Framework per un modello di dati. Questa classe eredita dalla classe Microsoft.EntityFrameworkCore.DbContext che gestisce le interazioni tra l'applicazione e il database. Per aggiungere il contesto del database, seguire questa procedura:
Creare una cartella denominata DbContext nella cartella radice del progetto.
Passare alla cartella DbContext e creare un file denominato
ToDoContext.cse quindi aggiungere il codice seguente:using Microsoft.EntityFrameworkCore; using ToDoListAPI.Models; namespace ToDoListAPI.Context; public class ToDoContext : DbContext { public ToDoContext(DbContextOptions<ToDoContext> options) : base(options) { } public DbSet<ToDo> ToDos { get; set; } }Aprire il file Program.cs nella cartella radice del progetto e aggiornarlo con il codice seguente:
// Add the following to your imports using ToDoListAPI.Context; using Microsoft.EntityFrameworkCore; //Register ToDoContext as a service in the application builder.Services.AddDbContext<ToDoContext>(opt => opt.UseInMemoryDatabase("ToDos"));
Nel frammento di codice precedente, il contesto di database viene registrato come servizio a livello di ambito nel provider di servizi dell'applicazione ASP.NET Core (noto anche come contenitore di iniezione delle dipendenze). È anche possibile configurare la ToDoContext classe per l'uso di un database in memoria per l'API Elenco ToDo.
Configurare un controller
I controller implementano in genere azioni Create, Read, Update e Delete (CRUD) per gestire le risorse. Poiché questa esercitazione è incentrata maggiormente sulla protezione degli endpoint API, vengono implementati solo due elementi di azione nel controller. Azione "Leggi tutto" per recuperare tutti gli elementi To-Do e azione "Crea" per aggiungere un nuovo elemento To-Do. Seguire questa procedura per aggiungere un controller al progetto:
Passare alla cartella radice del progetto e creare una cartella denominata Controllers.
Creare un file denominato
ToDoListController.csall'interno della cartella Controllers e aggiungere il codice della lastra caldaia seguente:
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Identity.Web;
using Microsoft.Identity.Web.Resource;
using ToDoListAPI.Models;
using ToDoListAPI.Context;
namespace ToDoListAPI.Controllers;
[Authorize]
[Route("api/[controller]")]
[ApiController]
public class ToDoListController : ControllerBase
{
private readonly ToDoContext _toDoContext;
public ToDoListController(ToDoContext toDoContext)
{
_toDoContext = toDoContext;
}
[HttpGet()]
[RequiredScopeOrAppPermission()]
public async Task<IActionResult> GetAsync(){...}
[HttpPost]
[RequiredScopeOrAppPermission()]
public async Task<IActionResult> PostAsync([FromBody] ToDo toDo){...}
private bool RequestCanAccessToDo(Guid userId){...}
private Guid GetUserId(){...}
private bool IsAppMakingRequest(){...}
}
Aggiungere codice al controller
In questa sezione si spiega come aggiungere codice al controller scaffolding creato nella sezione precedente. L'obiettivo è proteggere l'API, non crearla.
Importare i pacchetti necessari: Il
Microsoft.Identity.Webpacchetto è un wrapper intorno MSAL.NET che consente di gestire facilmente la logica di autenticazione, ad esempio la gestione della convalida dei token. Per assicurarsi che gli endpoint richiedano l'autorizzazione, viene usato il pacchetto predefinitoMicrosoft.AspNetCore.Authorization.Poiché sono state concesse autorizzazioni per chiamare questa API utilizzando autorizzazioni delegate per conto dell'utente o autorizzazioni dell'applicazione, dove il client agisce per proprio conto e non per conto dell'utente, è importante sapere se la chiamata viene effettuata dall'app in autonomia. Il modo più semplice per eseguire questa operazione consiste nel determinare se il token di accesso contiene l'attestazione
idtypfacoltativa. Questaidtypattestazione è il modo più semplice per l'API per determinare se un token è un token dell'app o un token app + utente. Si consiglia di abilitare la dichiarazione facoltativaidtyp.Se l'attestazione
idtypnon è abilitata, è possibile usare lerolesattestazioni escpper determinare se il token di accesso è un token dell'app o un token utente e un'app. Un token di accesso rilasciato da Microsoft Entra ID ha almeno una delle due attestazioni. I token di accesso emessi a un utente hanno l'attestazionescp. I token di accesso rilasciati a un'applicazione hanno l'attestazioneroles. I token di accesso che contengono entrambe le attestazioni vengono emessi solo agli utenti, in cui l'attestazionescpdesigna le autorizzazioni delegate, mentre l'attestazionerolesdesigna il ruolo dell'utente. I token di accesso che non soddisfano alcuna delle condizioni non devono essere considerati validi.private bool IsAppMakingRequest() { if (HttpContext.User.Claims.Any(c => c.Type == "idtyp")) { return HttpContext.User.Claims.Any(c => c.Type == "idtyp" && c.Value == "app"); } else { return HttpContext.User.Claims.Any(c => c.Type == "roles") && !HttpContext.User.Claims.Any(c => c.Type == "scp"); } }Aggiungere una funzione helper che determina se la richiesta effettuata contiene autorizzazioni sufficienti per eseguire l'azione desiderata. Controllare se è l'app che effettua la richiesta per proprio conto o se l'app effettua la chiamata per conto di un utente proprietario della risorsa specificata convalidando l'ID utente.
private bool RequestCanAccessToDo(Guid userId) { return IsAppMakingRequest() || (userId == GetUserId()); } private Guid GetUserId() { Guid userId; if (!Guid.TryParse(HttpContext.User.GetObjectId(), out userId)) { throw new Exception("User ID is not valid."); } return userId; }Inserire le definizioni di autorizzazione per proteggere i percorsi. Proteggere l'API aggiungendo l'attributo
[Authorize]alla classe controller. In questo modo, le azioni del controller possono essere chiamate solo se l'API viene chiamata con un'identità autorizzata. Le definizioni di autorizzazione definiscono i tipi di autorizzazioni necessari per eseguire queste azioni.[Authorize] [Route("api/[controller]")] [ApiController] public class ToDoListController: ControllerBase{...}Aggiungere autorizzazioni agli endpoint GET e POST. Eseguire questa operazione usando il metodo RequiredScopeOrAppPermission che fa parte dello spazio dei nomi Microsoft.Identity.Web.Resource . Si passano quindi ambiti e autorizzazioni a questo metodo tramite gli attributi RequiredScopesConfigurationKey e RequiredAppPermissionsConfigurationKey .
[HttpGet] [RequiredScopeOrAppPermission( RequiredScopesConfigurationKey = "AzureAD:Scopes:Read", RequiredAppPermissionsConfigurationKey = "AzureAD:AppPermissions:Read" )] public async Task<IActionResult> GetAsync() { var toDos = await _toDoContext.ToDos! .Where(td => RequestCanAccessToDo(td.Owner)) .ToListAsync(); return Ok(toDos); } [HttpPost] [RequiredScopeOrAppPermission( RequiredScopesConfigurationKey = "AzureAD:Scopes:Write", RequiredAppPermissionsConfigurationKey = "AzureAD:AppPermissions:Write" )] public async Task<IActionResult> PostAsync([FromBody] ToDo toDo) { // Only let applications with global to-do access set the user ID or to-do's var ownerIdOfTodo = IsAppMakingRequest() ? toDo.Owner : GetUserId(); var newToDo = new ToDo() { Owner = ownerIdOfTodo, Description = toDo.Description }; await _toDoContext.ToDos!.AddAsync(newToDo); await _toDoContext.SaveChangesAsync(); return Created($"/todo/{newToDo!.Id}", newToDo); }
Configurare il middleware API per l'uso del controller
Configurare quindi l'applicazione per riconoscere e usare i controller per la gestione delle richieste HTTP. Aprire il program.cs file e aggiungere il codice seguente per registrare i servizi controller nel contenitore di inserimento delle dipendenze.
builder.Services.AddControllers();
var app = builder.Build();
app.MapControllers();
app.Run();
Nel frammento di codice precedente, il AddControllers() metodo prepara l'applicazione all'uso dei controller registrando i servizi necessari mentre MapControllers() esegue il mapping delle route del controller per gestire le richieste HTTP in ingresso.
Esegui l'API
Eseguire l'API per assicurarsi che sia in esecuzione senza errori usando il comando dotnet run. Se si intende usare il protocollo HTTPS anche durante i test, è necessario considerare attendibile . Il certificato di sviluppo di NET.
Avviare l'applicazione digitando quanto segue nel terminale:
dotnet runUn output simile al seguente deve essere visualizzato nel terminale, che conferma che l'applicazione è in esecuzione
http://localhost:{port}e in ascolto delle richieste.Building... info: Microsoft.Hosting.Lifetime[0] Now listening on: http://localhost:{port} info: Microsoft.Hosting.Lifetime[0] Application started. Press Ctrl+C to shut down. ...
La pagina Web http://localhost:{host} visualizza un output simile all'immagine seguente. Ciò è dovuto al fatto che l'API viene chiamata senza autenticazione. Per effettuare una chiamata autorizzata, vedere Passaggi successivi per istruzioni su come accedere a un'API Web protetta.
Per un esempio completo di questo codice API, vedere il file di esempi di.