ASP.NET Core - Autenticação JWT (revisitado)
Neste artigo vamos recordar como implementar a autenticação JWT em uma aplicação ASP .NET Core. |
Como eu já escrevi alguns artigos sobre o assunto vou realizar uma abordagem bem objetiva e direta sem entrar em detalhes nos conceitos envolvidos.
Para saber mais sobre os Json Web Tokens - JWT consulte meus artigos:
Neste artigo vamos criar uma API ASP .NET Core, proteger os seus endpoints, gerar o token JWT, registrar usuários e tratar com a autorização baseada em roles usando o Identity.
Recursos usados:
Criando e configurando a API
Para criar um novo projeto de Web API no ambiente .NET Core usando a NET CLI, precisamos:
Vamos abrir um terminal de comandos usando o PowerShell e criar um diretório labs, e entrando dentro desta pasta vamos emitir o comando : dotnet new webapi -n apiagenda
Este comando vai criar a pasta apiagenda e nesta pasta vai criar o projeto web api.
Temos assim o projeto web api - apiagenda - criado que vai exibir uma lista de agendamentos.
Podemos agora buildar o projeto e a seguir executar a api criada digitando os comandos:
Abrindo um navegador e digitando o comando: https://localhost:5001/swagger/index.html teremos o resultado a seguir:
Temos a nossa apiagenda exibindo um único endpoint usando a interface do Swagger que foi incluída por padrão no template padrão que usamos para criar o projeto. Esse endpoint usa o controlador padrão criado que podemos até remover do projeto pois não vamos usá-lo.
Vamos criar um novo controlador para exibir uma lista de agendamentos.
Vamos abrir o projeto no VS Code digitando o comando : code .
Abaixo vemos o projeto aberto no VS Code:
Agora crie uma pasta Models no projeto e nesta pasta crie a classe Agenda:
public class Agenda { public int Id { get; set; } public string Evento { get; set; } public DateTime Data { get; set; } } |
A seguir crie um novo controlador na pasta Controllers chamado AgendaController com o seguinte código :
using System.Collections.Generic; using apiagenda.Models; using Microsoft.AspNetCore.Mvc; namespace apiagenda.Controllers |
Executando novamente o projeto e acessando o endpoint api/agenda temos o resultado:
Assim vemos que o ao acessar o endpoint api/agenda podemos obter a lista de agendamentos.
Vamos então iniciar a configuração para implementar a autenticação JWT.
Configurando a autenticação JWT
Para configurar a autenticação JWT no .NET Core, precisamos modificar o código do método ConfigureServices da classe Startup do projeto. Esta classe realiza a inicialização da aplicação e assim vamos habilitar a autenticação JWT.
Para isso temos que incluir no projeto o pacote: Microsoft.AspNetCore.Authentication.JwtBearer que contém recursos que habilitam o suporte para a autenticação baseada no JWT.
Abra um terminal de comandos, posicione-se na pasta do projeto e digite:
dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer
Após isso podemos modificar o método ConfigureServices incluindo o código em destaque para implementar a autenticação JWT:
public void ConfigureServices(IServiceCollection services) { services.AddAuthentication(opt => { opt.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; opt.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }) .AddJwtBearer(options => { options.TokenValidationParameters = new TokenValidationParameters { ValidateIssuer = true, ValidateAudience = true, ValidateLifetime = true, ValidateIssuerSigningKey = true, ValidIssuer = Configuration["Jwt:Issuer"], ValidAudience = Configuration["Jwt:Audience"], IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Jwt:Key"])) }; }); services.AddControllers(); services.AddSwaggerGen(c => { c.SwaggerDoc("v1", new OpenApiInfo { Title = "apiagenda", Version = "v1" }); }); } |
Neste código :
Invocamos o middleware AddAuthentication() e especificamos o esquema do portador JWT para ser o esquema de autenticação. Também especificamos várias opções para o esquema do portador(bearer) JWT.
Se você observar o objeto TokenValidationParameters, verá que ele indica se o emissor, a audiência, a vida útil e a chave de assinatura devem ser validados ou não. No exemplo usamos definindo como true.
Além disso, também especificamos um emissor válido, um público-alvo válido e uma chave de assinatura válida. Esses valores serão recuperados a partir do arquivo de configuração appsettings.json que vamos definir a seguir.
Abra o arquivo appsettings.json e inclua uma seção chamada Jwt (o nome pode ser qualquer um) no arquivo conforme mostrado a seguir:
{ "Jwt": { "Key": "aqui voce usa uma chaveSecreta para ser usada para assinar o token", "Issuer": "AlgumIssuer", "Audience": "AlgumaAudience" }, "Logging": { "LogLevel": { "Default": "Warning" } }, "AllowedHosts": "*" } |
-
Key é uma string secreta que é usada para
assinatura do token;
- Issuer - Indica a parte que esta emitindo o JWT;
- Audience - Indica os destinatários do JWT;
Agora temos que habilitar o middleware de autenticação incluindo o código abaixo em azul no método Configure da mesma classe:
public void Configure(IApplicationBuilder
app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); app.UseSwagger(); app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "apiagenda v1")); } app.UseHttpsRedirection(); app.UseAuthentication(); |
No código chamamos UseAuthentication() para conectar o middleware de autenticação ao pipeline HTTP.
Definindo a segurança dos endpoints da API
Vamos incluir o atributo [Authorize] no método Action GetAgendamentos da API de forma a restringir o acesso a somente usuários autenticados. Dessa forma somente os usuários que fizerem o Login válido poderão obter uma lista de agendamentos.
using System.Collections.Generic;
using apiagenda.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace apiagenda.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class AgendaController : ControllerBase
{
[HttpGet,Authorize]
public IActionResult GetAgendamentos()
{
List<Agenda> agenda = new List<Agenda>();
agenda.Add(new Agenda()
{
Id = 1,
Evento = "Curso DDD na prática",
Data = System.DateTime.Now
});
agenda.Add(new Agenda()
{
Id = 1,
Evento = "Evento - Design Patterns",
Data = System.DateTime.Now.AddDays(15)
});
agenda.Add(new Agenda()
{
Id = 1,
Evento = "Palestra - Os recursos do .NET 6.0",
Data = System.DateTime.Now.AddDays(30)
});
return new ObjectResult(agenda);
}
}
}
|
Agora ao tentar acessar o endpoint api/agenda iremos obter o erro : 401 Unauthorized
Precisamos então implementar o login para que o usuário possa se autenticar e acessar o endpoint.
Implementando o login
Para autenticar
usuários anônimos, temos que fornecer um endpoint de Login em nossa API
para que os usuários possam fazer login e acessar recursos protegidos. Um
usuário fornecerá um nome de usuário, uma senha e, se as credenciais forem
válidas, emitiremos um token JWT para o cliente solicitante.
Para isso vamos adicionar uma classe LoginViewModel
para manter as credenciais do usuário no servidor. A classe
LoginViewModel é uma classe simples que contém duas
propriedades: UserName e Password. Vamos criar essa
classe na pasta Models do projeto:
public class LoginViewModel
{
public string UserName { get; set; }
public string Password { get; set; }
}
|
A seguir vamos criar o controlador AuthenticationController na pasta Controllers onde vamos validar as credenciais do usuário. Se as credenciais forem válidas, emitiremos um token JWT. Para esta demonstração, vamos codificar o nome de usuário como 'macoratti' e a senha como 'Numsey#2021' para implementar um usuário fake e assim simplificar o exemplo. (Aqui poderíamos implementar o Identity e armazenar as credenciais do usuário em um banco de dados.)
Depois de validar as credenciais do usuário, vamos gerar um JWT com uma chave secreta. O JWT usa a chave secreta para gerar a assinatura. E essa chave secreta esta definida no arquivo appsettings.json.
Implementando o controlador AuthenticationController:
using System; using System.Collections.Generic; using System.IdentityModel.Tokens.Jwt; using System.Security.Claims; using System.Text; using apiagenda.Models; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Configuration; using Microsoft.IdentityModel.Tokens; namespace apiagenda.Controllers [HttpPost, Route("login")] var signinCredentials = new SigningCredentials(_secretKey, SecurityAlgorithms.HmacSha256); var tokeOptions = new JwtSecurityToken( var tokenString = new JwtSecurityTokenHandler().WriteToken(tokeOptions); return Ok(new { Token = tokenString }); } |
Entendendo o
código :
Criamos um método Action POST usando o verbo HttPost
que vai enviar as credenciais para validação para o servidor.
No
método de
Login, estamos criando um
SymmetricSecretKey com o valor da chave secreta _secretKey
definida no arquivo appsettings.json. Em seguida,
estamos criando o objeto SigningCredentials e, como
argumentos, fornecemos uma chave secreta e o nome do algoritmo que vamos
usar para encriptar o token.
As duas primeiras etapas são as etapas padrão com as quais você não precisa se
preocupar. A terceira etapa é aquela em que estamos interessados. Na terceira
etapa, estamos criando o objeto JwtSecurityToken
com alguns parâmetros importantes:
A seguir criamos uma representação string do token JWT chamando o método WriteToken em JwtSecurityTokenHandler. Por fim, estamos retornando o JWT em uma response. Como resposta, criamos um objeto anônimo que contém apenas a propriedade Token.
Agora é só alegria, vamos testar...
Executando o projeto no terminal do VS Code.
A seguir informando o userName - macoratti e password - Numsey#2021 e clicando em Execute teremos o seguinte resultado:
Vemos o token gerado, e, fazendo o download temos o token exibido a seguir:
{ "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2MjM1NDA3MTIsImlzcyI6Imh0dHBzOi8vb G9jYWxob3N0OjUwMDEiLCJhdWQiOiJodHRwczovL2xvY2FsaG9zdDo1MDAxIn0.F7WWmzYu8-GU-216 yCS6RFUHW4Fic-rN3HxlnAZeL0U" } |
Assim neste artigo vimos como gerar um token JWT de forma simples em uma aplicação ASP .NET Core usando o VS Code.
Para saber como usar o token com a interface do Swagger veja o artigo : ASP.NET Core - Usando o token JWT com o Swagger
Pegue o projeto implementado aqui: apiagenda1.zip (sem as referências)
"E ouvi uma grande voz do céu, que dizia: Eis aqui o
tabernáculo de Deus com os homens, pois com eles habitará, e eles serão o seu
povo, e o mesmo Deus estará com eles, e será o seu Deus."
Apocalipse 21:3
Referências:
ASP .NET Core 2 - MiniCurso Básico
ASP .NET Core - Macoratti
Conceitos - .NET Framework versus .NET Core
ASP .NET Core - Conceitos Básicos
ASP .NET Core MVC - CRUD básico com ADO .NET
ASP .NET Core - Implementando a segurança com .
ASP .NET Core - Apresentando Razor Pages
Minicurso ASP .NET Core 2.0 - Autenticação com JWT - I
Minicurso ASP .NET Core 2.0 - Autenticação com JWT - II