ASP .NET Core API - Autenticação e Atualização do token JWT - I


Hoje vamos iniciar a criação de uma API REST usando a ASP .NET Core 5.0 e implementar a autenticação JWT e a seguir mostrar como podemos atualizar o token JWT usado.

Vamos iniciar criando uma API ASP .NET Core para gerenciar eventos que usa um banco de dados SQLite usando o Visual Studio Code.

Os recursos usados serão:

Criando a API

Antes de iniciar vamos verificar se o ambiente esta com o .NET 5.0 instalado, digitando no prompt de comandos:

dotnet --version

A seguir precisamos instalar a ferramenta Entity Framework - dotnet ef - digitando o comando:

dotnet tool install --global dotnet-ef

Após isso vamos criar uma pasta onde vamos criar o projeto. Para o exemplo eu vou criar a pasta : md d:labs/apijwt

E a seguir vamos entrar na pasta e criar o projeto digitando:

dotnet new webapi -n "EventosWeb" -au none

Com isso teremos o projeto sendo criado na pasta EventosWeb.

A seguir vamos incluir os pacotes do Entity FrameworkCore no projeto:

dotnet add package Microsoft.EntityFrameworkCore.Sqlite
dotnet add package Microsoft.EntityFrameworkCore.Tools

Agora para abrir o projeto no VS Code digite : code.

Criando o modelo de domínio e o contexto

Vamos criar uma pasta Models no projeto e nesta pasta vamos criar a classe Evento:

using System;

namespace EventosWeb.Models
{
  public class Evento
 {
    public int Id { get; set; }
    public string Titulo { get; set; }
    public string Descricao { get; set; }
    public string Palestrante { get; set; }
    public DateTime DataEvento { get; set; }
    public bool Status { get; set; }
 }
}

Esta classe representa o nosso modelo de domínio para os eventos que a API vai gerenciar.

Agora vamos criar uma pasta DataContext no projeto e nesta pasta criar a classe ApplicationDbContext:

using EventosWeb.Models;
using Microsoft.EntityFrameworkCore;
namespace EventosWeb.DataContext
{
    public class ApplicationDbContext : DbContext
    {
        public DbSet<Evento> Eventos {get;set;}
        public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options)
        {
        }
    }
}

Esta classe representa o contexto da aplicação e faz a ponte entre a entidade e o banco de dados Sqlite.

No arquivo appsettings.json vamos definir a string de conexão com o SQLite:

{
  "ConnectionStrings": {
    "DefaultConnection": "DataSource=eventos.db;Cache=Shared"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*"
}

Com o nosso DbContext e a string de conexão estão prontos, precisamos atualizar a classe Startup para que possamos utilizar o DbContext do aplicativo dentro de nosso aplicativo.

No método ConfigureServices vamos registrar o serviço do contexto:

public void ConfigureServices(IServiceCollection services)
{
            services.AddDbContext<ApplicationDbContext>(options =>
                options.UseSqlite(
                    Configuration.GetConnectionString("DefaultConnection")));
            services.AddControllers();
            services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("v1", new OpenApiInfo { Title = "EventosWeb", Version = "v1" });
            });
}

No registro do serviço definimos o provedor do banco de dados SQLite e a string de conexão definida.

Podemos aplicar o Migrations para criar o banco de dados SQLite:

dotnet ef migrations add "Inicial "
dotnet ef database update

Com isso será criada a pasta Migrations no projeto e o arquivo de script gerado será usado para criar o banco de dados e a tabela no SQLite:

using System;
using Microsoft.EntityFrameworkCore.Migrations;
namespace EventosWeb.Migrations
{
    public partial class Inicial : Migration
    {
        protected override void Up(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.CreateTable(
                name: "Eventos",
                columns: table => new
                {
                    Id = table.Column<int>(type: "INTEGER", nullable: false)
                        .Annotation("Sqlite:Autoincrement", true),
                    Titulo = table.Column<string>(type: "TEXT", nullable: true),
                    Descricao = table.Column<string>(type: "TEXT", nullable: true),
                    Palestrante = table.Column<string>(type: "TEXT", nullable: true),
                    DataEvento = table.Column<DateTime>(type: "TEXT", nullable: false),
                    Status = table.Column<bool>(type: "INTEGER", nullable: false)
                },
                constraints: table =>
                {
                    table.PrimaryKey("PK_Eventos", x => x.Id);
                });
        }
        protected override void Down(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.DropTable(
                name: "Eventos");
        }
    }
}

Teremos assim o banco de dados eventos.db e a tabela Eventos criados.

Podemos verificar o banco e a tabela usando a ferramenta DB Browser que pode ser obtida neste site: https://sqlitebrowser.org/dl/

Após instalar basta abrir o banco criado no nosso projeto:

Criando o controlador

Vamos agora criar o controlador EventosController na pasta Controllers que representa a nossa API:

using System;
using System.Linq;
using System.Threading.Tasks;
using EventosWeb.DataContext;
using EventosWeb.Models;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;

namespace EventosWeb.Controllers
{
    [Route("api/v1/[controller]")]
    [ApiController]

    public class EventosController : ControllerBase
    {
        private readonly ApplicationDbContext _context;

        public EventosController(ApplicationDbContext context)
        {
            _context = context;
        }

    [HttpGet]
    public ActionResult GetEventos()
    {
        var eventos = _context.Eventos.ToList();
        return Ok(eventos);
    }

    [HttpGet("{id}")]
    public async Task<IActionResult> GetEvento(int id)
    {
        var evento = await _context.Eventos.FirstOrDefaultAsync(z => z.Id == id);

        if(evento == null)
            return NotFound();

        return Ok(evento);
    }

    [HttpPost]
    public async Task<IActionResult> CreateEvento(Evento data)
    {
        if(ModelState.IsValid)
        {
           await _context.Eventos.AddAsync(data);
           await _context.SaveChangesAsync();

            return CreatedAtAction("GetEvento", new {data.Id}, data);
        }

         return new JsonResult("Algo deu errado...") {StatusCode = 500};
    }

    [HttpPut("{id}")]
    public async Task<IActionResult> UpdateEvento(int id, Evento evento)
    {
        if(id != evento.Id)
            return BadRequest();
           

            if (evento is null)
            {
                throw new ArgumentNullException(nameof(evento));
            }

            var eventoExistente = await _context.Eventos.FirstOrDefaultAsync(z => z.Id == id);

        if(eventoExistente == null)
            return NotFound();

        eventoExistente.Titulo = evento.Titulo;
        eventoExistente.Descricao = evento.Descricao;
        eventoExistente.DataEvento = evento.DataEvento;
        eventoExistente.Status = evento.Status;

        await _context.SaveChangesAsync();

        return NoContent();
    }

    [HttpDelete("{id}")]
    public async Task<IActionResult> DeleteEvento(int id)
    {
        var evento = await _context.Eventos.FirstOrDefaultAsync(z => z.Id == id);

        if(evento == null)
            return NotFound();

        _context.Eventos.Remove(evento);
        await _context.SaveChangesAsync();

        return Ok(evento);
    }
  }
}

Com isso podemos testar a API usando a interface do Swagger.

Pegue o projeto aqui: EventosWeb1.zip (sem as referências)

Na próxima parte do artigo vamos implementar a autenticação JWT.

"Não me envergonho do evangelho, porque é o poder de Deus para a salvação de todo aquele que crê: primeiro do judeu, depois do grego."
Romanos 1:16

Referências:

 


José Carlos Macoratti