ASP.NET Core 3.1 - CRUD : Web API com EF Core e Tokens JWT
Hoje teremos um roteiro básico para criar Web APIs para realizar o CRUD com ASP .NET Core 3.1 e EF Core usando Tokens JWT. |
Hoje temos um roteiro básico que explica o desenvolvimento de APIs REST usando a ASP.NET Core 3.1, fazendo a conexão com banco de dados existentes via Entity Framework, e criando um token JWT para proteção da API.
Vamos criar uma aplicação ASP.NET Core Web API bem simples para realizar o CRUD básico usando o SQL Server e as tabelas Produtos e Usuarios que iremos criar. Portanto vamos usar uma abordagem DataBaseFirst para variar um pouco.
Os recursos usados foram:
A seguir o mapa do nosso roteiro:
Agora ao trabalho...
1- O que é uma API Rest ?
Devido ao
crescente número nas diferentes variedades de clientes (aplicativos móveis,
SPAs baseados em navegador, aplicativos desktop, aplicativos IOT etc.),
precisamos transferir dados dos servidores para os clientes de uma forma
melhor e que seja independente da tecnologia e dos servidores.
As APIs REST resolvem esse problema de uma forma
simples e direta.
REST significa - Representational State Transfer - ou Transferência de Estado Representacional e as APIs REST podem ser baseadas no protocolo HTTP (mas isso não é obrigatório) e fornecem aos aplicativos a capacidade de se comunicar usando o formato JSON, sendo executadas em servidores web.
O REST não é uma linguagem nem um framework, é um estilo de arquitetura para fornecer padrões entre sistemas de computadores na Web, com o objetivo de facilitar a comunicação entre os sistemas.
Nota: O
termo RESTful é usado para indicar capacidade de
determinado sistema aplicar os princípios de REST.
O estilo arquitetural REST que vamos considerar é
representado pelas seguintes entidades:
Resource : Os recursos são entidades identificáveis de forma única (por exemplo: dados de um banco de dados, imagens ou qualquer dado). Qualquer informação que pode ser nomeada pode ser um recurso.
Endpoint : É um recurso pode ser acessado através de um identificador de URL;
Resource Method : Embora não seja obrigatório, vamos considerar o método HTTP como sendo o tipo de solicitação que um cliente envia para um servidor web. Os principais métodos HTTP usados nas APIs REST criadas na plataforma .NET são: GET, POST PUT e DELETE. (Lembre-se que REST não é HTTP)
Header HTTP: Um cabeçalho HTTP é um par de chave-valor usado para compartilhar informações adicionais entre um cliente e servidor, como:
2- O que é um Token JWT
Vejamos agora o
que é
um JWT bearer token, que vamos usar para proteger
a nossa WEB API REST.
JWT significa JSON Web Token
e, é um padrão aberto que define uma maneira melhor de transferir dados com
segurança entre duas entidades (cliente e servidor).
Um token JWT é assinado digitalmente usando uma
chave secreta por um provedor de token ou servidor de autenticação. Um JWT ajuda
o servidor de recursos a verificar os dados do token usando a mesma chave
secreta, para que você possa confiar nos dados.
O JWT consiste nas três partes a seguir:
O token JWT final será assim: Header.PayLoad.Signature
Exemplo de token codificado:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4g
RG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
Existe um fluxo para criação do token JWT que veremos mais adiante.
3 - Criar uma Web API REST com ASP .NET Core 3.1
Abra o Visual Studio 2019 Community versão 16.5 ou superior e faça o seguinte:
Etapa 1: Vá para
File->New Project (ou estando na
Start Window clique em New
Project);
Etapa 2: Selecione o template ASP .NET Core Web
Application e clique em Next;
Etapa 4: Digite o nome do projeto - InventarioNet
- e sua localização e clique em Create;
Etapa 5: Selecione o template .NET Core,
ASP.NET Core 3.1 e API
(destacado a seguir);
Ao clicar no botão Create o projeto será criado com a estrutura abaixo exibida na janela Solution Explorer:
Vamos remover a API WeatherForecastController e a respectiva classe WeatherForecastcs que são criados por padrão.
4. Instalar os pacotes Nuget
Agora vamos adicionar os pacotes Nuget ao projeto e podemos fazer isso via menu Tools-> Manage Nuget Packages for Solution ou via menu Tools-> Package Manager Console.
Ao instalar você deve marcar todos os projetos e sempre instalar as últimas versões estáveis de cada pacote.
Vamos usar a última opção e na janela de comandos digitar : Package-Install<nome-pacote> -Version xxx
1- Install-package Microsoft.VisualStudio.Web.CodeGeneration.Design -Version 3.1.2
Este pacote ajuda
a gerar controladores e views e contém o comando
dotnet-aspnet-codegenerator.
2- Install-Package
Microsoft.EntityFrameworkCore.Tools -Version 3.1.4
Este pacote ajuda a criar contexto de banco de dados e classes de modelo a
partir do banco de dados.
3- Install-Package
Microsoft.EntityFrameworkCore.SqlServer -Version 3.1.4
Este pacote fornece o provedor de banco de dados permite que o Entity Framework
Core trabalhe com o SQL Server.
4-
Install-Package
Microsoft.AspNetCore.Authentication.JwtBearer -Version 3.1.4
Este pacote fornece suporte para criar e validar um token JWT.
5- Install-Package System.IdentityModel.Tokens.Jwt -Version 6.5.1
Este é o middleware que permite que um aplicativo ASP.NET Core receber um token bearer no pipeline do request.
Após concluir a instalação destes pacotes o seu projeto não pode apresentar nenhum erro ou conflito entre pacotes. O arquivo de projeto InventarioNet.csproj deve estar assim:
5. Gerar as entidades e o contexto a
partir do banco de dados
Para variar um pouco vamos usar a abordagem DatabaseFirst e partir de um banco de dados e tabelas que já existem.
Temos um banco de dados chamado InventarioDB no SQL Server e as seguintes tabelas:
1- Produtos - Script SQL
USE [InventarioDB] GO CREATE TABLE [dbo].[Produtos]( [ProdutoId] [int] IDENTITY(1,1) NOT NULL, [Nome] [nvarchar](100) NOT NULL, [Preco] [decimal](18, 2) NOT NULL, [Estoque] [int] NOT NULL, [Imagem] [nvarchar](250) NULL, CONSTRAINT [PK_Produtos] PRIMARY KEY CLUSTERED( [ProdutoId] ASC ); |
Vou incluir 3 produtos na tabela Produtos para realizar os testes:
2- Usuarios - Script SQL
USE [InventarioDB] GO CREATE TABLE [dbo].[Usuarios]( [UsuarioId] [int] IDENTITY(1,1) NOT NULL, [Nome] [nvarchar](100) NOT NULL, [Login] [nvarchar](80) NOT NULL, [Senha] [nvarchar](80) NOT NULL, [Ativo] [bit] NOT NULL, [Email] [nvarchar](250) NULL, CONSTRAINT [PK_Usuarios] PRIMARY KEY CLUSTERED ( [UsuarioId] ASC ); |
Vou incluir 1 usuário na tabela Usuarios para testar:
Assim vamos gerar as entidades de domínio que serão obtidas a partir destas tabelas usando o comando Scaffold DbContext para fazer a engenharia reversa.
O comando usado para gerar o modelo de entidades a partir do banco de dados é :
dotnet ef dbcontext scaffold <string de conexão>
Provider -o Models -f -c arquivoContexto
Onde :
dotnet ef dbcontext - comando
<string de conexão> - a string de conexão do banco
de dados usado
Provider - o provedor do banco de dados
-o Models - a pasta de sáida das classes geradas
-f - sobrescreve um código anteriormente gerado
-c arquivoContexto - o nome do
DbContext usado na aplicação
O banco de dados InventarioDB.mdf possui a seguinte string de conexão (obtida a partir do Server Explorer):
'Data Source=Macoratti;Initial Catalog=InventarioDB;Integrated Security=True'
O comando para gerar as entidades deverá ficar assim:
dotnet ef dbcontext scaffold "Data Source=Macoratti;Initial Catalog=InventarioDB;Integrated Security=True" Microsoft.EntityFrameworkCore.SqlServer -o Models -f -c AppDbContext |
Nota: A versão da ferramenta Scaffold deve ser a mesma que a versão do pacote Microsoft.EntityFrameworkCore.Tools. No meu ambiente tive que atualizar a versão usando o comando abaixo:
Agora podemos executar comando Scafold DbContext na janela de comandos do Prompt de Comandos:
Obs: Você deve estar na pasta do projeto.
Ao final teremos as entidades Produtos e Usuarios e o arquivo AppDbContext gerados na pasta Models:
Eu vou alterar o nome das entidades para o singular: Produto e Usuario.
Abaixo temos o código da classe de contexto AppDbContext:
using Microsoft.EntityFrameworkCore;
namespace InventarioNET.Models
{
public partial class AppDbContext : DbContext
{
public AppDbContext()
{}
public AppDbContext(DbContextOptions<AppDbContext> options)
: base(options)
{ }
public virtual DbSet<Produto> Produtos { get; set; }
public virtual DbSet<Usuario> Usuarios { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
optionsBuilder.UseSqlServer
("Data Source=Macoratti;Initial Catalog=InventarioDB;Integrated Security=True");
}
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Produto>(entity =>
{
entity.HasKey(e => e.ProdutoId);
entity.Property(e => e.Imagem).HasMaxLength(250);
entity.Property(e => e.Nome)
.IsRequired()
.HasMaxLength(100);
entity.Property(e => e.Preco).HasColumnType("decimal(18, 2)");
});
modelBuilder.Entity<Usuario>(entity =>
{
entity.HasKey(e => e.UsuarioId);
entity.Property(e => e.Email).HasMaxLength(250);
entity.Property(e => e.Login)
.IsRequired()
.HasMaxLength(80);
entity.Property(e => e.Nome)
.IsRequired()
.HasMaxLength(100);
entity.Property(e => e.Senha)
.IsRequired()
.HasMaxLength(80);
});
OnModelCreatingPartial(modelBuilder);
}
partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
}
}
|
Vamos remover a string de conexão desta classe para o arquivo appsettings.json abaixo:
{
"ConnectionStrings": {
"DefaultConnection": "Data Source=Macoratti;Initial Catalog=InventarioDB;Integrated Security=True"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*"
}
|
E a seguir vamos registrar o contexto no método ConfigureServices da classe Startup:
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<AppDbContext>(options =>
{
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"));
});
services.AddControllers();
}
|
Dessa forma poderemos injetar este serviço nos controladores.
Na próxima parte do artigo vamos continuar criando a nossa Web API no projeto.
"Muitas são,
Senhor meu Deus, as maravilhas que tens operado para conosco, e os teus
pensamentos não se podem contar diante de ti; se eu os quisera anunciar, e deles
falar, são mais do que se podem contar."
Salmos 40:5
Referências:
C# - Imprimindo um arquivo texto
C# - Usando OpenFileDialog - Macoratti
Compactando e Descompactando arquivos
-
C# - Lendo e escrevendo em
arquivos textos e binários -
VB.NET - Conversão entre tipos de
variáveis
Minicurso ASP .NET Core 2.0 -
Autenticação com JWT - I
ASP .NET Core - Implementando e
consumindo JWT