ASP
.NET Core -
Implementando a autenticação JWT
- I
![]() |
Neste artigo vamos recordar como implementar a autenticação JWT na ASP .NET Core. |
Eu já apresentei os conceitos e utilização do padrão JSON Web Tokens em duas vídeo aulas:
Como eu expliquei nesses vídeos, a JWT significa JSON Web Tokens, e, é um padrão aberto ( RFC-7519 ) para passar dados do usuário entre o cliente e o servidor. O JWT possui muitas vantagens em relação à autenticação tradicional de cookies.
O JWT é mais seguro e também pode ser usado com outros tipos de clientes além do cliente web. Em um cenário Single Pagel Application o JWT é uma opção preferencial para implementar a autenticação.
Um token JWT consiste em três partes:
Ao contrário dos cookies, que são passados automaticamente para o servidor, o
token JWT precisa ser explicitamente passado para o servidor pelo cliente.
Então, um fluxo simplificado de operações seria o seguinte:
1- O cliente envia credenciais de segurança, como nome de
usuário e senha, para o servidor para validação;
2- O servidor valida o nome de usuário e a senha;
3- Se as credenciais forem válidas, o servidor gera e emite um token JWT para o
cliente;
4- O cliente recebe o token e o armazena em algum lugar;
5- Ao solicitar qualquer recurso ou ação do servidor, o cliente adiciona o token
JWT emitido anteriormente no cabeçalho Authorization da requisição;
6- O servidor lê o cabeçalho de autorização para recuperar o token JWT;
7- Se o token for válido, o servidor executará a ação solicitada pelo cliente;
Então, basta pensar no token JWT como um ticket. Se a requisição recebida tiver
um ticket válido, ela poderá acessar um recurso.
Dessa forma
para implementar a autenticação baseada em JWT, precismos executar as seguintes
etapas:
1- Armazenar os detalhes do JWT em um arquivo de
configuração.
2- Ativar o esquema de autenticação JWT na inicialização do aplicativo.
3- Criar algum mecanismo que valide o nome de usuário e a senha e emita um token
JWT.
4- Crie uma API protegida (Authorize)
5- Invocar a API de um cliente usando o token
Neste artigo vamos seguir esse roteiro básico.
Recursos Usados:
Criando o projeto ASP .NET Core Web API
Abra o VS 2017 Community e clique em New Project;
Selecione o template ASP .NET Core Web Application e informe o nome ApiJwt1 e clique em OK;
Selecione a seguir o template API para criar a Web API clique no botão OK.
Ao final teremos um projeto com uma estrutura padrão e um controlador ValuesController na pasta Controllers que iremos usar para testar a autenticação via JWT.
Para isso vamos incluir o atributo Authorize no método Get e Get(int id) do controlador ValuesController :
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
[Authorize]
[HttpGet]
public ActionResult<IEnumerable<string>> Get()
{
return new string[] { "Maria", "Paulo", "Pedro", "Marcia", "Armando" };
}
[Authorize]
// GET api/values/5
[HttpGet("{id}")]
public ActionResult<string> Get(int id)
{
return "Marta";
}
....
}
|
Nesta etapa vamos definir a classe de domínio User na pasta Models do projeto com o código abaixo:
public class User
{
public string UserName { get; set; }
public string Password { get; set; }
} |
1- Armazenar os detalhes do JWT em um arquivo de configuração.
Inclua no arquivo appsettings.json do projeto uma seção Jwt com as informações a seguir:
{
"Jwt": {
"Key": "dfusa7f9090dfsiaisfdasfiuasjasdfa90cvzxxzcvasf998dfspd",
"Issuer": "MacorattiIssuer",
"Audience": "MacorattiAudience"
}
} |
Você pode definir o nome da seção a seu gosto, e, ela define 3 chaves:
2- Ativar o esquema de autenticação JWT na inicialização do aplicativo.
Abra o arquivo Startup e modifique o método ConfigureServices() conforme mostrado abaixo:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
services.AddAuthentication
(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"]))
};
});
}
|
Neste código chamamos o método 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 JWT. Se você observar atentamente 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.
Também especificamos um emissor válido, um público-alvo válido e uma chave de assinatura válida. Esses valores são recuperados do arquivo de configuração que definimos anteriormente.
Os namespaces usados para poder usar esses recursos são :
Para concluir precisamos incluir a linha de código app.UseAuthentication no método Configure():
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseMvc();
}
|
Precisamos desse código para vincular o middleware de autenticação no pipeline HTTP.
3- Criar algum mecanismo que valide o nome de usuário e a senha e emita um token JWT.
Vamos implementar agora o código que vai validar as credenciais do usuário : username e password.
Para isso vamos criar um novo Controlador chamado SegurancaController na pasta Controllers e vamos definir 3 métodos:
Esse controlador vai precisar ter uma instância de IConfiguration para poder acessar as informações no arquivo de configuração.
using Api_Jwt1.Model;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.IdentityModel.Tokens;
using System;
using System.IdentityModel.Tokens.Jwt;
using System.Text;
namespace Api_Jwt1.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class SegurancaController : ControllerBase
{
private readonly IConfiguration _config;
public SegurancaController(IConfiguration configuration)
{
_config = configuration;
}
[HttpPost]
public IActionResult Login([FromBody]User loginDetails)
{
bool resultado = ValidarUsuario(loginDetails);
if (resultado)
{
var tokenString = GerarTokenJwt();
return Ok(new { token = tokenString });
}
else
{
return Unauthorized();
}
}
private bool ValidarUsuario(User loginDetails)
{
if (loginDetails.UserName == "mac" && loginDetails.Password == "numsey")
{
return true;
}
else
{
return false;
}
}
public string GerarTokenJwt()
{
var issuer = _config["Jwt:Issuer"];
var audience = _config["Jwt:Audience"];
var expiry = DateTime.Now.AddMinutes(60);
var securityKey = new SymmetricSecurityKey
(Encoding.UTF8.GetBytes(_config["Jwt:Key"]));
var credentials = new SigningCredentials
(securityKey, SecurityAlgorithms.HmacSha256);
var token = new JwtSecurityToken(issuer: issuer,
audience: audience,
expires: DateTime.Now.AddMinutes(120),
signingCredentials: credentials);
var tokenHandler = new JwtSecurityTokenHandler();
var stringToken = tokenHandler.WriteToken(token);
return stringToken;
}
}
}
|
Observe que a
Action Login esta marcada com o atributo [HttPost]
e portanto essa ation será invocada pelo aplicativo cliente e o cliente, de
alguma forma, fornecerá os detalhes do usuário, como nome de usuário e senha.
A seguir chamamos o método auxiliar ValidaUsuario()
para verificar se o nome de usuário e a senha são válidos. Se as credenciais do
usuário forem válidas, chamamos GerarTokenJwt()
para gerar um token JWT. O token de string é retornado ao cliente com o status
HTTP de Ok (código de status - 200).
Observe que não implementamos o acesso a um banco de dados. Para simplificar o método ValidarUsuario definimos uma validação fixa, mas você poderia usar o ASP.NET Core Identity ou qualquer técnica personalizada para validar um usuário. Se as credenciais do usuário forem válidas, retornamos true, caso contrário, retornaremos false.
O método mais importante é o método GerarTokenJwt() onde temos :
A recuperação do emissor, do público-alvo e da chave do arquivo de configuração. Em seguida, temos a criação de uma nova SymmetricSecurityKey com base na chave.
O objeto
SigningCredentials é gerado com base na
SymmetricSecurityKey. Observe que usamos o
algoritmo HS256 ao gerar a assinatura digital.
Agora podemos seguir em frente e criar um token JWT. Isso é feito usando a
classe JwtSecurityToken. Passamos o emissor, o
público-alvo, um DateTime de expiração para o token e as credenciais de
assinatura no construtor.
Queremos o JWT em um formato de string para que possa ser facilmente enviado ao
cliente. Isso é feito usando a classe
JwtSecurityTokenHandler. O método WriteToken()
aceita um JwtSecurityToken criado anteriormente e o
retorna como uma string de formato serializado compact JSON.
Podemos agora testar a nossa implementação fazendo o Login e gerando um Token e a seguir acessando a API.
Usando o Postman - Gerando o Token e acessando a API
Para instalar o Postman acesse esse link : https://www.getpostman.com/apps ou abra o Google Chrome e digite postam e a seguir clique no link: Postman - Chrome Web Store
Execute o projeto no VS 2017.
A seguir abra o Postman e vamos definir a seguinte requisição para criar um usuário:
1 - https://localhost:44355/api/seguranca
E no corpo da
requisição (Body) usando o formato JSON (application/json)
vamos passr as credencias:
{
"Username" : "mac",
"Password" : "numsey"
}
Conforme mostra a figura a abaixo:
Ao clicar no botão Send vemos o token gerado exibido na resposta.
Agora já temos o token, e, vamos acessar a API ValuesController enviando uma requisição com o token.
Para isso vamos copiar o token obtido e montar a seguinte requisição GET no Postman:
3- https://localhost:44355/api/values
A seguir em Authorization marque a opção Bearer Token e informe o token conforme gerado figura abaixo:
Observe que obtivemos os valores retornados pelo método GET (que esta protegido com Authorize) indicando que o nosso token foi validado com sucesso.
Na próxima parte do artigo veremos como consumir essa API usando jQuery.
Salmos 18:2
Referências: