Eryx em 09 Jul 2019
Este texto contém orientações para implantação de tokens de autenticação JWT em um projeto IdentityServer4 com ASP.NET Identity.
O cenário ideal é manter um projeto IdentityServer4 independente (separado) e implementar o ASP.NET Identity com controle de usuários e perfis para cada aplicação. No momento em que um End Point
JSON Web Tokens (JWT) é um padrão para representação de claims entre duas partes de maneira segura. Veja abaixo a definição oficial no site (jwt.io)[https://jwt.io/].
JSON Web Tokens are an open, industry standard RFC 7519 method for representing claims securely between two parties. ----
Incluir middleware JWTBearer em ConfigureServices na classe startup.cs do seu projeto IdentityServer4.
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:Issuer"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Jwt:Key"]))
};
});
Será necessário resolver e ou referênciar as seguintes dependências
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using System.Text;
Incluir chave de configuração para fornecer Key e Issuer para as requisições JWT no arquivo appsettings.json.
{
"ConnectionStrings": {
"DefaultConnection": "Data Source=db-stigeo-...;database=...;trusted_connection=no;User ID=observatorio;Password=..."
},
"Jwt": {
"Key": "veryVerySecretKey",
"Issuer": "http://localhost:5000/"
},
"Application": {
...
Criar TokenController para fornecer endpoint para criação de tokens JWT em TokenController.cs.
Este controller inicializa SignInManager
private IConfiguration _config;
private readonly SignInManager<ApplicationUser> _signInManager;
public TokenController(IConfiguration config, SignInManager<ApplicationUser> signInManager)
{
_config = config;
_signInManager = signInManager;
}
As classes LoginModel e UserModel representam as informações de login e usuário referenciadas pelo TokenController.
public class LoginModel
{
public string Username { get; set; }
public string Password { get; set; }
}
private class UserModel
{
public string Name { get; set; }
public string Email { get; set; }
public DateTime Birthdate { get; set; }
}
O método CreateTokenAsyn coordena a geração do token JWT.
[AllowAnonymous]
[HttpPost]
public async Task<IActionResult> CreateTokenAsync([FromBody]LoginModel login)
{
IActionResult response = Unauthorized();
var user = await AuthenticateAsync(login);
if (user != null)
{
var tokenString = BuildToken(user);
response = Ok(new { token = tokenString });
}
return response;
}
O método AuthenticateAsync valida usuário e senha informados.
private async Task<LoginViewModel> AuthenticateAsync(LoginModel login)
{
LoginViewModel user = new LoginViewModel();
var result = await _signInManager.PasswordSignInAsync(login.Username, login.Password, false, lockoutOnFailure: false);
if (result.Succeeded)
{
user.Email = login.Username;
user.Password = login.Password;
return user;
}
return null;
}
A autenticação do código acima utiliza o método PasswordSignInAsync da instância de SigninManager
private UserModel Authenticate(LoginModel login)
{
UserModel user = null;
if (login.Username == "eryx" && login.Password == "secret")
{
user = new UserModel { Name = "Eryx", Email = "eryx.guimaraes@gmail.com" };
}
return user;
}
O método BuildToken gera o token JWT com o método WriteToken utilizando o token criado com a instância do método JwtSecurityToken.
private string BuildToken(LoginViewModel user)
{
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["Jwt:Key"]));
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
var token = new JwtSecurityToken(
_config["Jwt:Issuer"],
_config["Jwt:Issuer"],
expires: DateTime.Now.AddMinutes(30),
signingCredentials: creds);
return new JwtSecurityTokenHandler().WriteToken(token);
}
Você pode obter o token JWT enviando uma requisição POST para o endpoint http://localhost:52553/api/token enviando o JSON na aba Body do Postman com os campo username e password conforme exemplo abaixo.
{
"username": "eryx.guimaraes@gmail.com",
"password": "12qw!@QW"
}
Caso o usuário e senha informados sejam válidos, será retornado o token json ilustrado a seguir.
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NjI2NzUwMzUsImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3Q6NTI1NTMvIiwiYXVkIjoiaHR0cDovL2xvY2FsaG9zdDo1MjU1My8ifQ.lvbcV1N0_b0qgfyCLT9sgBCvcIjFMxSAUZcW3CpSjpY"
}
Em seguida, utilize o token obtido para fazer uma requisição ao endpoint de alteração da senha (Account/ChangePass). Crie uma requisição POST para o url http://localhost:52553/Account/ChangePass/?returnUrl=/home/index e envie o token no Header através do parâmetro Authorization com o valor Bearer seguido de espaço e o token obtido no passo anterior. O Body da requisição deverá conter os campos OldPassword, NewPassword e ConfirmPassword com respectivos valores.
Documentação oficial https://identityserver4.readthedocs.io/en/latest/