ASP .NET Core - Minimal API com PostgreSQL e EF Core - II
Neste artigo veremos como criar uma API usando a abordagem das Minimal APIs para realizar um CRUD básico em um banco de dados PostgreSQL usando o EF Core. |
Continuando o artigo anterior vamos agora implementar a segurança em nossa API e aproveitar para reorganizar os endpoints agrupando-os na interface do Swagger.
Para agrupar os endpoints vamos usar o método WithTags() que permite agrupar os endpoints na interface do Swagger. Assim vamos aplicar o método WithTags("Categorias") para os endpoints de categorias e WithTags("Produtos") para os endpoints de produtos.
A titulo de exemplo abaixo temos código para os endpoints que retornam todas as categorias e todos os produtos usando o método WithTags:
app.MapGet("/categorias", async (AppDbContext db) => await db.Categorias.ToListAsync() ) .WithTags("Categorias");
app.MapGet("/produtos", async (AppDbContext db) => |
Assim aplicando o código para os respectivos endpoints de categorias e produtos teremos o seguinte resultado na exibição da interface do Swagger:
Vamos agora implementar a segurança em nossa aplicação usando a autenticação JWT.
Para saber mais sobre a autenticação JWT consulte os artigos :
Em nosso projeto a implementação vai seguir o roteiro padrão e eu não vou implementar o Identity para gerenciar os usuários. Vamos definir um usuário padrão com nome e senha para testar a geração do token Jwt e fazer a autenticação JWT na API de forma simplificar o processo.
Implementando a autenticação JWT
Até o momento
qualquer usuário anônimo pode acessar a nossa API pois ela esta aberta.
Para proteger a nossa API vamos implementar a autenticação JWT.
JWT (JSON Web Token) é um padrão definido na
RFC 7519 para
realizar autenticação entre duas partes por meio de um token assinado que
autentica uma requisição web. Esse token é um código em Base64 que
armazena objetos JSON com os dados que permitem a autenticação da requisição.
Os dados nele contidos podem ser validados a qualquer momento pois o token é
assinado digitalmente.
Em uma autenticação baseada em token, o cliente troca suas credenciais(exemplo:
login e senha) por um token, depois disso em vez de enviar as credenciais a cada
requisição o cliente so envia o token pra a autenticação e autorização
Para consultar a API é necessário obter um token de acesso temporário (Bearer).
Esse token possui um tempo de validade e, sempre que expirado, o passo de
requisição de um novo token de acesso deve ser repetido.
Vamos iniciar incluindo em nosso projeto o pacote :
Para representar o usuário vamos criar a classe UserModel na pasta Models:
namespace CatalogoApi.Models;
public class UserModel |
A seguir vamos criar no projeto a pasta Services e nesta pasta criar a interface ITokenService e sua implementação na classe TokenService
1- ITokenService
using CatalogoApi.Models; namespace CatalogoApi.Services;
public interface ITokenService |
2- TokenService
using CatalogoApi.Models; using Microsoft.IdentityModel.Tokens; using System.IdentityModel.Tokens.Jwt; using System.Security.Claims; using System.Text; namespace CatalogoApi.Services; public class TokenService : ITokenService var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(key)); var token = new JwtSecurityToken(issuer: issuer,
var tokenHandler = new JwtSecurityTokenHandler(); |
Acabamos de definir a implementação do token JWT e que vai usar as configurações que precisamos definir no arquivo appsettings.json na seção Jwt :
{ "ConnectionStrings": { "DefaultConnection": "<string de conexão ;" }, "Jwt": { "Key": "#5994471ABB01112AFCC18159F6CC74B4F511B99806DA59B3CAF5A9C173CACFC5@", "Issuer": "Macoratti.net", "Audience": "http://www.macoratti.net" }, "Logging": { "LogLevel": { "Default": "Information", "Microsoft.AspNetCore": "Warning" } }, "AllowedHosts": "*" } |
A seguir vamos definir a seguinte configuração do middleware de autenticação no arquivo Program, que vai permitir usar a autenticação bearer e também validar o token gerado :
... builder.Services.AddSingleton<ITokenService>(new TokenService()); builder.Services.AddAuthentication ValidIssuer = builder.Configuration["Jwt:Issuer"], builder.Services.AddAuthorization(); ... app.UseAuthentication(); |
Neste código registramos o serviço da geração do token e definimos a autenticação usando o schema Jwt e incluímos o serviço da autorização.
Agora precisamos incluir na classe Program um endpoint para fazer o login do usuário e a geração do token.
Para isso estou definindo um usuário com nome 'macoratti' e senha 'numsey#123' e a seguir invocando o método para gerar o token :
|
Com isso podemos testar a geração do token e a seguir fazer a chamada a um endpoint protegido. Para fazer um teste vamos proteger os endpoints que usam MapGet e retornam todas as categorias e todos os produtos incluindo o método de extensão .RequireAuthorization();
app.MapGet("/categorias", async (AppDbContext db) =>
await db.Categorias.ToListAsync()) .WithTags("Categorias") .RequireAuthorization();
app.MapGet("/produtos", async (AppDbContext db) =>
|
Para testar a nossa implementação teremos que gerar o token e enviar este token com cada requisição para acessar os endpoints seguros.
Para facilitar este procedimento podemos configurar o Swagger na API ASP.NET Core para poder enviar o token JWT em cada request bastando para isso informar uma única vez o token.
Eu apresento isso em detalhes neste artigo : ASP.NET Core - Usando o token JWT com o Swagger
Para fazer isso temos que ajustar a configuração do Swagger no arquivo Program do projeto incluindo o código abaixo:
builder.Services.AddSwaggerGen(c => { c.SwaggerDoc("v1", new OpenApiInfo { Title = "apiagenda", Version = "v1" });
c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme() |
Agora é só alegria...
Vamos executar o projeto e tentar acessar um endpoint protegido GET /categorias e a seguir vamos fazer o login, gerar o token e informar o token no Swagger e depois vamos acessar o endpoint novamente. Veja o resultado:
Na próxima parte do artigo iremos mostrar como organizar o código da classe Program.
Pegue o projeto completo aqui : CatalogoApi_Inicio_Jwt.zip
"Então ele
disse: "Jesus, lembra-te de mim quando entrares no teu Reino".
Jesus lhe respondeu: "Eu lhe garanto: Hoje você estará comigo no paraíso"."
Lucas 23:42,43
Referências:
ASP .NET Core - Implementando a segurança com
ASP.NET Core MVC - Criando um Dashboard .
C# - Gerando QRCode - Macoratti
ASP .NET - Gerando QRCode com a API do Google
ASP .NET Core 2.1 - Como customizar o Identity
Usando o ASP .NET Core Identity - Macoratti
ASP .NET Core - Apresentando o IdentityServer4
ASP .NET Core 3.1 - Usando Identity de cabo a rabo