L'autenticazione e l'autorizzazione sono due concetti fondamentali in qualsiasi applicazione web moderna. Senza una corretta gestione degli utenti e dei loro privilegi, un'applicazione è vulnerabile a accessi non autorizzati e comportamenti indesiderati. Implementare un sistema di controllo degli accessi basato su ruoli (RBAC) è una delle soluzioni più comuni ed efficaci. In questo contesto, esploreremo come integrare il controllo degli accessi basato su ruoli (RBAC) in un'applicazione ASP.NET Core Minimal API utilizzando JSON Web Token (JWT) per l'autenticazione.

L'implementazione di un sistema RBAC in ASP.NET Core 9.0 richiede una serie di passaggi, dall'impostazione dell'applicazione alla configurazione di JWT per garantire che solo gli utenti con i privilegi giusti possano accedere a determinate risorse. L'approccio di questa guida si concentra sulla creazione e gestione di ruoli utente e sull'utilizzo dei JWT per proteggere le risorse API.

Per prima cosa, è fondamentale installare le librerie necessarie. L'applicazione dovrà essere configurata con Entity Framework Core per la gestione degli utenti, bcrypt per l'hashing delle password e JWT per la generazione e la validazione dei token di autenticazione. Una volta impostata la base dell'applicazione, dovremo definire i modelli di dati, configurare il DbContext, gestire la creazione e l'assegnazione dei ruoli e implementare la protezione delle risorse basata su questi ruoli.

Creazione e configurazione del progetto

  1. Impostare un nuovo progetto ASP.NET Core 9.0:
    Prima di tutto, apriamo il terminale e creiamo una nuova cartella per il progetto. Successivamente, creiamo un'applicazione API minima con il comando:

    cpp
    dotnet new webapi

    Poi apriamo il progetto in Visual Studio Code:

    css
    code .
  2. Installazione dei pacchetti necessari:
    L'applicazione avrà bisogno dei seguenti pacchetti:

    • Entity Framework Core per la gestione del database.

    • bcrypt per l'hashing delle password.

    • JWT per l'autenticazione.

    • Scalar UI per la gestione dei test dell'API.

    I pacchetti si installano con i comandi:

    csharp
    dotnet add package Microsoft.EntityFrameworkCore.SqlServer dotnet add package Microsoft.EntityFrameworkCore.Design dotnet add package BCrypt.Net-Next dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer dotnet add package Scalar.AspNetCore
  3. Definire i modelli e il DbContext:
    Dopo aver configurato i pacchetti, è il momento di definire i modelli di dati. Creiamo una cartella Models e iniziamo a definire il modello utente, ApiUser.cs:

    csharp
    public class ApiUser {
    [Key] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int Id { get; set; } public string Username { get; set; } = "";
    public string Password { get; set; } = "";
    public string Name { get; set; } = "";
    public string Email { get; set; } = "";
    }

    Successivamente, creiamo i DTO per la registrazione e il login, nonché per il token JWT:

    csharp
    public class UserLogin {
    public string UserName { get; set; } = "";
    public string Password { get; set; } = ""; } public class UserToken {
    public string Token { get; set; } = "";
    public string ExpiredAt { get; set; } = "";
    public string Message { get; set; } = "";
    }

    Per implementare l'RBAC, creiamo i modelli Role e UserRole:

    csharp
    public class Role { [Key] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int Id { get; set; }
    public string Name { get; set; } = "";
    public List<ApiUser>? Users { get; set; } } public class UserRole { [Key] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int Id { get; set; } public ApiUser? User { get; set; } = null!;
    public Role? Role { get; set; } = null!;
    }
  4. Configurazione del DbContext e dell'autenticazione JWT:
    Una volta definiti i modelli, è il momento di configurare il DbContext e l'autenticazione JWT nel file Program.cs. Qui dobbiamo registrare il contesto del database e configurare il sistema di autenticazione con JWT, definendo una chiave segreta per la firma dei token:

    csharp
    builder.Services.AddDbContext<AppDbContext>(options =>
    options.UseSqlServer(builder.Configuration.GetConnectionString("MyDB"))); var key = builder.Configuration["AppSettings:Secret"]; var keyBytes = Encoding.ASCII.GetBytes(key ?? "default_secret_key"); builder.Services.AddAuthentication(o => { o.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; o.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }) .AddJwtBearer(o => { o.RequireHttpsMetadata = false; o.SaveToken = true; o.TokenValidationParameters = new TokenValidationParameters { ValidateIssuerSigningKey = true, IssuerSigningKey = new SymmetricSecurityKey(keyBytes), ValidateIssuer = false, ValidateAudience = false, }; }); builder.Services.AddAuthorization(options => { var policy = new AuthorizationPolicyBuilder(JwtBearerDefaults.AuthenticationScheme) .RequireAuthenticatedUser() .Build(); options.DefaultPolicy = policy; });

Test e gestione dell'autenticazione e autorizzazione

Una volta completata la configurazione, possiamo testare il sistema di autenticazione e autorizzazione. Per fare ciò, è possibile utilizzare strumenti come Scalar UI o l'estensione REST Client di Visual Studio Code. Dopo aver creato un utente con l'endpoint di registrazione, effettuiamo il login e copiamo il JWT dal risultato della risposta.

Per accedere alle risorse protette, dobbiamo includere il token JWT nell'intestazione della richiesta come "Bearer Token". L'accesso al profilo dell'utente o a risorse riservate sarà quindi consentito solo agli utenti che dispongono di un token JWT valido.

Considerazioni aggiuntive

La gestione dei ruoli e la protezione dei dati sono aspetti cruciali per garantire la sicurezza di un'applicazione. In un sistema RBAC, ogni utente ha uno o più ruoli che determinano le sue autorizzazioni. È fondamentale che la creazione e l'assegnazione dei ruoli siano gestite in modo sicuro e che i permessi siano applicati correttamente a tutte le risorse sensibili. Inoltre, l'uso di JWT consente di implementare un sistema di autenticazione scalabile e facilmente integrabile con altre applicazioni o servizi.

Come Creare un'API RESTful con ASP.NET Core Minimal API: Un'Introduzione Pratica

La creazione di servizi web in modalità RESTful è una pratica fondamentale nello sviluppo moderno, e ASP.NET Core Minimal API, introdotto con la versione 9.0, offre un modo semplice ed efficiente per costruire tali API. In questa sezione, esploreremo alcuni esercizi pratici che ti guideranno nella creazione di un'API RESTful con ASP.NET Core Minimal API, trattando le operazioni più comuni come la gestione delle richieste HTTP, l'elaborazione delle risposte e la documentazione tramite Swagger.

Uno degli aspetti principali di ASP.NET Core Minimal API è la sua sintassi concisa e l'approccio minimalista, che permette agli sviluppatori di concentrarsi sulle funzionalità principali senza la complessità di configurazioni estese. Ad esempio, la creazione di un'API RESTful che supporta vari metodi HTTP (GET, POST, PUT, DELETE) richiede solo poche righe di codice, semplificando notevolmente il processo.

Creazione di un Servizio RESTful con ASP.NET Core 9.0

Iniziamo con un esercizio pratico per creare un semplice servizio RESTful utilizzando ASP.NET Core 9.0. In questo esercizio, esploreremo come gestire le richieste e inviare risposte appropriate a seconda del tipo di operazione richiesta. Creeremo un'applicazione API che permetterà di interagire con una lista di elementi tramite i metodi GET, POST, PUT e DELETE.

Passaggi Pratici

  1. Creare un nuovo progetto ASP.NET Core Minimal API:
    Apri un terminale e naviga alla directory desiderata. Usa il comando:

    arduino
    mkdir restfulapi
    cd restfulapi dotnet new webapi

    Dopo aver creato il progetto, aprilo nel tuo editor di codice preferito (Visual Studio Code, ad esempio).

  2. Modificare il progetto per l'API Minimal:
    Una volta aperto il progetto, sostituisci il contenuto di Program.cs per aggiungere i metodi di gestione per i vari endpoint. Ecco un esempio di implementazione:

    • GET: Restituire una lista di elementi.

      csharp
      var items = new List<string> { "Item 1", "Item 2", "Item 3" }; app.MapGet("/items", () => items);
    • POST: Aggiungere un nuovo elemento alla lista.

      csharp
      app.MapPost("/items", (string item) => {
      items.Add(item); return Results.Created($"/items/{items.Count - 1}", item); });
    • PUT: Aggiornare un elemento esistente.

      csharp
      app.MapPut("/items/{id}", (int id, string item) => { if (id < 0 || id >= items.Count) return Results.NotFound(); items[id] = item; return Results.NoContent(); });
    • DELETE: Eliminare un elemento dalla lista.

      csharp
      app.MapDelete("/items/{id}", (int id) => {
      if (id < 0 || id >= items.Count) return Results.NotFound(); items.RemoveAt(id); return Results.Ok(); });
  3. Compilare e Avviare l'Applicazione:
    Dopo aver aggiunto il codice sopra, torna al terminale e compila l'applicazione con:

    nginx
    dotnet build

    Avvia il progetto con:

    arduino
    dotnet run
  4. Testare l'API:
    Puoi utilizzare strumenti come Postman o un client REST integrato nel tuo editor per testare gli endpoint. Prova a eseguire le operazioni GET, POST, PUT e DELETE per interagire con la tua API e verificare che risponda correttamente.

Documentazione API con Swagger

Un'altra parte fondamentale nello sviluppo di API è la documentazione. Con ASP.NET Core 9.0, l'integrazione con Swagger è estremamente semplice e ti permette di generare automaticamente una documentazione interattiva per la tua API. Per aggiungere Swagger al tuo progetto, basta includere un paio di righe di codice nel file Program.cs:

  1. Abilitare Swagger:
    Nel file Program.cs, aggiungi il supporto per Swagger:

    csharp
    app.AddEndpointsApiExplorer();
    app.UseSwagger(); app.UseSwaggerUI();
  2. Visualizzare la Documentazione:
    Una volta avviato il progetto, puoi accedere alla documentazione Swagger tramite l'URL:

    bash
    http://localhost:5000/swagger

    Questo ti permette di esplorare i vari endpoint, vedere le risposte e persino effettuare richieste direttamente dal browser.

Gestione degli Errori e Logging

Un altro aspetto cruciale nella costruzione di API robuste è la gestione degli errori e il logging. ASP.NET Core Minimal API semplifica anche questi aspetti, consentendo di gestire facilmente le eccezioni e registrare informazioni utili per il debugging. Ecco come aggiungere una gestione di base per gli errori:

  1. Gestire le Eccezioni:
    Puoi utilizzare un middleware globale per intercettare le eccezioni non gestite e restituire una risposta coerente:

    csharp
    app.UseExceptionHandler("/error");
  2. Aggiungere il Logging:
    Il logging in ASP.NET Core è molto semplice da configurare. Aggiungi una riga per registrare eventi nel ciclo di vita dell'applicazione:

    csharp
    var logger = app.Logger;
    logger.LogInformation("Applicazione avviata.");

Middleware e Filtri

Infine, l'uso di middleware e filtri è essenziale per gestire il flusso di richieste e risposte in modo ottimale. I middleware consentono di eseguire operazioni su tutte le richieste, come l'autenticazione, la gestione delle CORS (Cross-Origin Resource Sharing), o l'aggiunta di intestazioni personalizzate. I filtri, invece, sono utili per aggiungere logica aggiuntiva prima o dopo l'esecuzione di un'azione.

L'approccio di ASP.NET Core Minimal API permette di implementare facilmente middleware personalizzati e filtri, senza la complessità di altre soluzioni basate su controller.

Considerazioni Importanti

Quando si sviluppa un'API RESTful, è fondamentale non solo concentrarsi sulla scrittura del codice ma anche pensare a come ottimizzare la sicurezza, le performance e l'usabilità dell'API. Aggiungere validazione dei dati, gestione avanzata degli errori, e caching per migliorare la performance sono passaggi necessari per realizzare un'API scalabile e sicura. Non dimenticare inoltre di testare accuratamente l'API in vari scenari di utilizzo per garantire la sua robustezza in produzione.

Come Migrare i Servizi Esistenti a ASP.NET Core 9.0: Implementazione di un Servizio Web di Calcolatrice

Nel contesto della migrazione di servizi esistenti verso ASP.NET Core 9.0, l'integrazione del supporto OpenAPI offre una notevole esperienza di sviluppo migliorata e una maggiore aderenza agli standard industriali. In questa sezione, esploreremo un esempio pratico di implementazione di un servizio web minimalista utilizzando ASP.NET Core 9.0, sviluppando un'API per una calcolatrice in grado di eseguire operazioni aritmetiche di base.

Sviluppo del Servizio di Calcolatrice

Il progetto che svilupperemo è un servizio web di calcolatrice che esegue operazioni aritmetiche come somma, sottrazione, moltiplicazione e divisione. Questo esempio ci permette di approfondire come gestire diverse tipologie di richieste HTTP e come eseguire operazioni aritmetiche di base, utilizzando l'API minima di ASP.NET Core 9. La creazione di un servizio come questo non solo dimostra la potenza di ASP.NET Core, ma permette anche di acquisire una solida base nella gestione di API semplici ma efficaci.

Creazione del Progetto

  1. Creazione del Progetto ASP.NET Core Minimal API
    Il primo passo è aprire una finestra di terminale e creare un nuovo progetto per l'API. Esegui i seguenti comandi:

    arduino
    mkdir calculatorapi
    cd calculatorapi dotnet new webapi code .
  2. Definizione del Record Numerico
    Una volta aperto il progetto, è necessario definire un tipo di record che rappresenti i numeri e il risultato delle operazioni. Aggiungilo alla fine del file Program.cs:

    csharp
    record Numeric(double Number1, double Number2, double Result = 0);
  3. Implementazione degli Endpoint della Calcolatrice
    Ora possiamo implementare gli endpoint per le operazioni aritmetiche di base. Utilizzando il record Numeric, aggiungiamo gli endpoint per somma, sottrazione, moltiplicazione e divisione. Ecco come aggiungere i vari endpoint nel file Program.cs:

    • Somma:

      csharp
      calculatorApi.MapPost("/add", (Numeric numbers) => {
      var result = numbers.Number1 + numbers.Number2; return Results.Ok(new Numeric(numbers.Number1, numbers.Number2, result)); });
    • Sottrazione:

      csharp
      calculatorApi.MapPost("/subtract", (Numeric numbers) => { var result = numbers.Number1 - numbers.Number2; return Results.Ok(new Numeric(numbers.Number1, numbers.Number2, result)); });
    • Moltiplicazione:

      csharp
      calculatorApi.MapPost("/multiply", (Numeric numbers) => {
      var result = numbers.Number1 * numbers.Number2; return Results.Ok(new Numeric(numbers.Number1, numbers.Number2, result)); });
    • Divisione:

      csharp
      calculatorApi.MapPost("/divide", (Numeric numbers) => { if (numbers.Number2 == 0) { return Results.BadRequest("Impossibile dividere per zero"); } var result = numbers.Number1 / numbers.Number2; return Results.Ok(new Numeric(numbers.Number1, numbers.Number2, result)); });

Ogni operazione aritmetica prende un oggetto Numeric come input, esegue l'operazione e restituisce un nuovo oggetto Numeric con il risultato.

Compilazione e Avvio del Servizio

Una volta implementati gli endpoint, il passo successivo è compilare ed eseguire il progetto. Utilizza il terminale per farlo:

arduino
dotnet run

Se desideri utilizzare un profilo HTTPS, puoi avviare l'applicazione con il comando:

arduino
dotnet run --launch-profile https

Test del Servizio di Calcolatrice

Per testare il servizio appena creato, è possibile utilizzare strumenti come Postman o l'estensione REST Client. Ecco come strutturare le richieste per testare le operazioni:

  • Somma:

    bash
    POST http://localhost:5003/api/calculator/add
    Content-Type: application/json { "Number1": 10, "Number2": 5 }
  • Sottrazione:

    bash
    POST http://localhost:5003/api/calculator/subtract Content-Type: application/json { "Number1": 10, "Number2": 5 }
  • Moltiplicazione:

    bash
    POST http://localhost:5003/api/calculator/multiply
    Content-Type: application/json { "Number1": 10, "Number2": 5 }
  • Divisione:

    bash
    POST http://localhost:5003/api/calculator/divide Content-Type: application/json { "Number1": 10, "Number2": 5 }

Considerazioni Importanti

Il metodo utilizzato per il trattamento dei dati (in questo caso, un record Numeric) offre numerosi vantaggi, in particolare per la sua semplicità e chiarezza nel gestire le informazioni. L'approccio con i record consente di passare e restituire facilmente dati complessi come oggetti immutabili, senza la necessità di manipolare manualmente i singoli parametri.

Inoltre, ASP.NET Core 9.0 con il suo supporto integrato per OpenAPI facilita ulteriormente la documentazione automatica delle API, migliorando la comprensione e l'interoperabilità delle interfacce. Questo rende più semplice per i team di sviluppo e gli utenti finali interagire con i servizi.

Anche se questa guida riguarda un esempio relativamente semplice, i concetti introdotti possono essere applicati in contesti più complessi. Per esempio, una gestione avanzata degli errori, come la gestione delle divisioni per zero, può essere estesa con meccanismi di validazione più sofisticati, migliorando ulteriormente l'affidabilità del servizio.

In conclusione, lavorare con ASP.NET Core Minimal API e l'uso di record rappresenta un approccio elegante e funzionale per creare applicazioni web efficienti e facilmente manutenibili.