Skip to content

Commit 5f6417f

Browse files
committed
#279 - Refresh Token na API de Identidade - feature/sp8/#279
1 parent 54531fe commit 5f6417f

14 files changed

+609
-107
lines changed
-388 KB
Binary file not shown.
-417 KB
Binary file not shown.

src/services/JSE.Identidade.API/Configuration/ApiConfig.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using JSE.WebAPI.Core.IdentityConfiguration;
1+
using JSE.Identidade.API.Services;
2+
using JSE.WebAPI.Core.IdentityConfiguration;
23
using JSE.WebAPI.Core.User;
34
using NetDevPack.Security.JwtSigningCredentials.AspNetCore;
45

@@ -10,6 +11,7 @@ public static IServiceCollection AddApiConfiguration(this IServiceCollection ser
1011
{
1112
services.AddControllers();
1213

14+
services.AddScoped<AuthenticationService>();
1315
services.AddScoped<IAspNetUser, AspNetUser>();
1416

1517
return services;

src/services/JSE.Identidade.API/Configuration/IdentityConfig.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ public static IServiceCollection AddIdentityConfiguration(this IServiceCollectio
1212
IConfiguration configuration)
1313
{
1414

15+
var appSettingsSection = configuration.GetSection("AppTokenSettings");
16+
services.Configure<AppTokenSettings>(appSettingsSection);
17+
1518
services.AddJwksManager(options => options.Algorithm = Algorithm.ES256)
1619
.PersistKeysToDatabaseStore<ApplicationDbContext>();
1720

Lines changed: 40 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,29 @@
1-
using System.IdentityModel.Tokens.Jwt;
2-
using System.Security.Claims;
3-
using System.Text;
1+
using System;
2+
using System.Threading.Tasks;
3+
using JSE.Core.Messages.Integration;
4+
using JSE.MessageBus;
45
using Microsoft.AspNetCore.Identity;
56
using Microsoft.AspNetCore.Mvc;
6-
using Microsoft.Extensions.Options;
7-
using Microsoft.IdentityModel.Tokens;
7+
using JSE.Core.Messages.Integration;
88
using JSE.Identidade.API.Models;
9-
using JSE.WebAPI.Core.Controllers;
9+
using JSE.Identidade.API.Services;
1010
using JSE.MessageBus;
11-
using JSE.Core.Messages.Integration;
12-
using JSE.WebAPI.Core.IdentityConfiguration;
13-
using JSE.WebAPI.Core.User;
14-
using NetDevPack.Security.JwtSigningCredentials.Interfaces;
11+
using JSE.WebAPI.Core.Controllers;
1512

1613
namespace JSE.Identidade.API.Controllers
1714
{
1815
[Route("api/identidade")]
1916
public class AuthController : MainController
2017
{
21-
private readonly SignInManager<IdentityUser> _signInManager;
22-
private readonly UserManager<IdentityUser> _userManager;
23-
private readonly AppSettings _appSettings;
24-
private readonly IAspNetUser _aspNetUser;
25-
private readonly IJsonWebKeySetService _jwksService;
26-
18+
private readonly AuthenticationService _authenticationService;
2719
private readonly IMessageBus _bus;
2820

29-
public AuthController(SignInManager<IdentityUser> signInManager,
30-
UserManager<IdentityUser> userManager,
31-
IOptions<AppSettings> appSettings,
32-
IMessageBus bus,
33-
IAspNetUser aspNetUser,
34-
IJsonWebKeySetService jwksService)
21+
public AuthController(
22+
AuthenticationService authenticationService,
23+
IMessageBus bus)
3524
{
36-
_signInManager = signInManager;
37-
_userManager = userManager;
38-
_appSettings = appSettings.Value;
25+
_authenticationService = authenticationService;
3926
_bus = bus;
40-
_aspNetUser = aspNetUser;
41-
_jwksService = jwksService;
4227
}
4328

4429
[HttpPost("nova-conta")]
@@ -53,19 +38,19 @@ public async Task<ActionResult> Registrar(UsuarioRegistroViewModel usuarioRegist
5338
EmailConfirmed = true
5439
};
5540

56-
var result = await _userManager.CreateAsync(user, usuarioRegistro.Senha);
41+
var result = await _authenticationService.UserManager.CreateAsync(user, usuarioRegistro.Senha);
5742

5843
if (result.Succeeded)
5944
{
6045
var clienteResult = await RegistrarCliente(usuarioRegistro);
6146

62-
if(!clienteResult.ValidationResult.IsValid)
47+
if (!clienteResult.ValidationResult.IsValid)
6348
{
64-
await _userManager.DeleteAsync(user);
49+
await _authenticationService.UserManager.DeleteAsync(user);
6550
return CustomResponse(clienteResult.ValidationResult);
6651
}
6752

68-
return CustomResponse(await GerarJwt(usuarioRegistro.Email));
53+
return CustomResponse(await _authenticationService.GerarJwt(usuarioRegistro.Email));
6954
}
7055

7156
foreach (var error in result.Errors)
@@ -79,15 +64,14 @@ public async Task<ActionResult> Registrar(UsuarioRegistroViewModel usuarioRegist
7964
[HttpPost("autenticar")]
8065
public async Task<ActionResult> Login(UsuarioLoginViewModel usuarioLogin)
8166
{
82-
8367
if (!ModelState.IsValid) return CustomResponse(ModelState);
8468

85-
var result = await _signInManager.PasswordSignInAsync(usuarioLogin.Email, usuarioLogin.Senha,
69+
var result = await _authenticationService.SignInManager.PasswordSignInAsync(usuarioLogin.Email, usuarioLogin.Senha,
8670
false, true);
8771

8872
if (result.Succeeded)
8973
{
90-
return CustomResponse(await GerarJwt(usuarioLogin.Email));
74+
return CustomResponse(await _authenticationService.GerarJwt(usuarioLogin.Email));
9175
}
9276

9377
if (result.IsLockedOut)
@@ -100,91 +84,42 @@ public async Task<ActionResult> Login(UsuarioLoginViewModel usuarioLogin)
10084
return CustomResponse();
10185
}
10286

103-
private async Task<UsuarioRespostaLoginViewModel> GerarJwt(string email)
104-
{
105-
var user = await _userManager.FindByEmailAsync(email);
106-
var claims = await _userManager.GetClaimsAsync(user);
107-
108-
var identityClaims = await ObterClaimsUsuario(claims, user);
109-
var encodedToken = CodificarToken(identityClaims);
110-
111-
return ObterRespostaToken(encodedToken, user, claims);
112-
}
113-
114-
private async Task<ClaimsIdentity> ObterClaimsUsuario(ICollection<Claim> claims, IdentityUser user)
87+
private async Task<ResponseMessage> RegistrarCliente(UsuarioRegistroViewModel usuarioRegistro)
11588
{
116-
var userRoles = await _userManager.GetRolesAsync(user);
89+
var usuario = await _authenticationService.UserManager.FindByEmailAsync(usuarioRegistro.Email);
11790

118-
claims.Add(new Claim(JwtRegisteredClaimNames.Sub, user.Id));
119-
claims.Add(new Claim(JwtRegisteredClaimNames.Email, user.Email));
120-
claims.Add(new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()));
121-
claims.Add(new Claim(JwtRegisteredClaimNames.Nbf, ToUnixEpochDate(DateTime.UtcNow).ToString()));
122-
claims.Add(new Claim(JwtRegisteredClaimNames.Iat, ToUnixEpochDate(DateTime.UtcNow).ToString(), ClaimValueTypes.Integer64));
91+
var usuarioRegistrado = new UsuarioRegistradoIntegrationEvent(
92+
Guid.Parse(usuario.Id), usuarioRegistro.Nome, usuarioRegistro.Email, usuarioRegistro.Cpf);
12393

124-
foreach (var userRole in userRoles)
94+
try
12595
{
126-
claims.Add(new Claim("role", userRole));
96+
return await _bus.RequestAsync<UsuarioRegistradoIntegrationEvent, ResponseMessage>(usuarioRegistrado);
12797
}
128-
129-
var identityClaims = new ClaimsIdentity();
130-
identityClaims.AddClaims(claims);
131-
132-
return identityClaims;
133-
}
134-
135-
private string CodificarToken(ClaimsIdentity identityClaims)
136-
{
137-
var tokenHandler = new JwtSecurityTokenHandler();
138-
139-
var currentIssuer = $"{_aspNetUser.ObterHttpContext().Request.Scheme}://{_aspNetUser.ObterHttpContext().Request.Host}";
140-
141-
var key = _jwksService.GetCurrent();
142-
var token = tokenHandler.CreateToken(new SecurityTokenDescriptor
98+
catch
14399
{
144-
Issuer = currentIssuer,
145-
Subject = identityClaims,
146-
Expires = DateTime.UtcNow.AddHours(1),
147-
SigningCredentials = key
148-
});
149-
150-
return tokenHandler.WriteToken(token);
100+
await _authenticationService.UserManager.DeleteAsync(usuario);
101+
throw;
102+
}
151103
}
152104

153-
private UsuarioRespostaLoginViewModel ObterRespostaToken(string encodedToken, IdentityUser user, IEnumerable<Claim> claims)
105+
[HttpPost("refresh-token")]
106+
public async Task<ActionResult> RefreshToken([FromBody] string refreshToken)
154107
{
155-
return new UsuarioRespostaLoginViewModel
108+
if (string.IsNullOrEmpty(refreshToken))
156109
{
157-
AccessToken = encodedToken,
158-
ExpiresIn = TimeSpan.FromHours(1).TotalSeconds,
159-
UsuarioToken = new UsuarioTokenViewModel
160-
{
161-
Id = user.Id,
162-
Email = user.Email,
163-
Claims = claims.Select(c => new UsuarioClaimViewModel { Type = c.Type, Value = c.Value })
164-
}
165-
};
166-
}
167-
168-
private static long ToUnixEpochDate(DateTime date)
169-
=> (long)Math.Round((date.ToUniversalTime() - new DateTimeOffset(1970, 1, 1, 0, 0, 0, TimeSpan.Zero)).TotalSeconds);
170-
171-
private async Task<ResponseMessage> RegistrarCliente(UsuarioRegistroViewModel usuarioRegistro)
172-
{
173-
var usuario = await _userManager.FindByEmailAsync(usuarioRegistro.Email);
174-
175-
var usuarioRegistrado = new UsuarioRegistradoIntegrationEvent(
176-
Guid.Parse(usuario.Id), usuarioRegistro.Nome, usuarioRegistro.Email, usuarioRegistro.Cpf);
110+
AddProcessingError("Refresh Token inválido");
111+
return CustomResponse();
112+
}
177113

114+
var token = await _authenticationService.ObterRefreshToken(Guid.Parse(refreshToken));
178115

179-
try
180-
{
181-
return await _bus.RequestAsync<UsuarioRegistradoIntegrationEvent, ResponseMessage>(usuarioRegistrado);
182-
}
183-
catch
116+
if (token is null)
184117
{
185-
await _userManager.DeleteAsync(usuario);
186-
throw;
118+
AddProcessingError("Refresh Token expirado");
119+
return CustomResponse();
187120
}
121+
122+
return CustomResponse(await _authenticationService.GerarJwt(token.UserName));
188123
}
189124
}
190125
}

src/services/JSE.Identidade.API/Data/ApplicationDbContext.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
1+
using JSE.Identidade.API.Models;
2+
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
23
using Microsoft.EntityFrameworkCore;
34
using NetDevPack.Security.JwtSigningCredentials;
45
using NetDevPack.Security.JwtSigningCredentials.Store.EntityFrameworkCore;
@@ -10,5 +11,7 @@ public class ApplicationDbContext : IdentityDbContext, ISecurityKeyContext
1011
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options) { }
1112

1213
public DbSet<SecurityKeyWithPrivate> SecurityKeys { get; set; }
14+
15+
public DbSet<RefreshToken> RefreshTokens { get; set; }
1316
}
1417
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
namespace JSE.Identidade.API.Extensions
2+
{
3+
public class AppTokenSettings
4+
{
5+
public int RefreshTokenExpiration { get; set; }
6+
}
7+
}

0 commit comments

Comments
 (0)