From fc9da89ebe541430ae7bf74cd3ab304a6a6d27c7 Mon Sep 17 00:00:00 2001 From: sanchezvem Date: Thu, 28 May 2026 14:05:47 +0100 Subject: [PATCH] Added refresh token endpoint --- .../DTO/Refresh/Request/RefreshTokenDto.cs | 6 ++ .../Refresh/Response/GetRefreshTokenDto.cs | 6 ++ .../Endpoints/Refresh/RefreshTokenEndpoint.cs | 62 +++++++++++++++++++ .../Endpoints/Users/ConnectUserEndpoint.cs | 2 +- PyroFetes/Program.cs | 2 +- 5 files changed, 76 insertions(+), 2 deletions(-) create mode 100644 PyroFetes/DTO/Refresh/Request/RefreshTokenDto.cs create mode 100644 PyroFetes/DTO/Refresh/Response/GetRefreshTokenDto.cs create mode 100644 PyroFetes/Endpoints/Refresh/RefreshTokenEndpoint.cs diff --git a/PyroFetes/DTO/Refresh/Request/RefreshTokenDto.cs b/PyroFetes/DTO/Refresh/Request/RefreshTokenDto.cs new file mode 100644 index 00000000..ab2c503e --- /dev/null +++ b/PyroFetes/DTO/Refresh/Request/RefreshTokenDto.cs @@ -0,0 +1,6 @@ +namespace PyroFetes.DTO.Refresh.Request; + +public class RefreshTokenDto +{ + public string? Token { get; set; } +} \ No newline at end of file diff --git a/PyroFetes/DTO/Refresh/Response/GetRefreshTokenDto.cs b/PyroFetes/DTO/Refresh/Response/GetRefreshTokenDto.cs new file mode 100644 index 00000000..ac16d1e6 --- /dev/null +++ b/PyroFetes/DTO/Refresh/Response/GetRefreshTokenDto.cs @@ -0,0 +1,6 @@ +namespace PyroFetes.DTO.Refresh.Response; + +public class GetRefreshTokenDto +{ + public string? Token { get; set; } +} \ No newline at end of file diff --git a/PyroFetes/Endpoints/Refresh/RefreshTokenEndpoint.cs b/PyroFetes/Endpoints/Refresh/RefreshTokenEndpoint.cs new file mode 100644 index 00000000..b11b4184 --- /dev/null +++ b/PyroFetes/Endpoints/Refresh/RefreshTokenEndpoint.cs @@ -0,0 +1,62 @@ +using System.IdentityModel.Tokens.Jwt; +using FastEndpoints; +using FastEndpoints.Security; +using PyroFetes.DTO.Refresh.Request; +using PyroFetes.DTO.Refresh.Response; +using PyroFetes.Models; +using PyroFetes.Repositories; +using PyroFetes.Specifications.Users; + +namespace PyroFetes.Endpoints.Refresh; + +public class RefreshTokenEndpoint(UsersRepository usersRepository) : Endpoint +{ + public override void Configure() + { + Post("/refresh"); + AllowAnonymous(); + } + + public override async Task HandleAsync(RefreshTokenDto req, CancellationToken ct) + { + try + { + JwtSecurityTokenHandler handler = new(); + JwtSecurityToken? token = handler.ReadJwtToken(req.Token); + string? username = token.Claims.FirstOrDefault(c => c.Type == "Name")?.Value; + + if (string.IsNullOrWhiteSpace(username)) + { + await Send.UnauthorizedAsync(ct); + return; + } + + User? login = await usersRepository.SingleOrDefaultAsync(new GetUserByNameSpec(username), ct); + if (login == null) + { + await Send.UnauthorizedAsync(ct); + return; + } + + string jwtToken = JwtBearer.CreateToken(o => + { + o.SigningKey = "v9!Qx7#Lk2@pZ8$wR6!tN5%uF3&cD9^mH1*eY4"; + o.ExpireAt = DateTime.UtcNow.AddMinutes(15); + if (login.Fonction is not null) o.User.Roles.Add(login.Fonction); + o.User.Claims.Add(("Name", login.Name)!); + o.User.Claims.Add(("Id", login.Id.ToString())!); + }); + + GetRefreshTokenDto responseDto = new() + { + Token = jwtToken + }; + + await Send.OkAsync(responseDto, ct); + } + catch + { + await Send.UnauthorizedAsync(ct); + } + } +} \ No newline at end of file diff --git a/PyroFetes/Endpoints/Users/ConnectUserEndpoint.cs b/PyroFetes/Endpoints/Users/ConnectUserEndpoint.cs index 14314c0b..d7931fac 100644 --- a/PyroFetes/Endpoints/Users/ConnectUserEndpoint.cs +++ b/PyroFetes/Endpoints/Users/ConnectUserEndpoint.cs @@ -31,7 +31,7 @@ public class ConnectUserEndpoint(UsersRepository usersRepository) : Endpoint { - o.SigningKey = "ThisIsASuperSecretJwtKeyThatIsAtLeast32CharsLong"; + o.SigningKey = "v9!Qx7#Lk2@pZ8$wR6!tN5%uF3&cD9^mH1*eY4"; o.ExpireAt = DateTime.UtcNow.AddMinutes(15); if (user.Fonction is not null) o.User.Roles.Add(user.Fonction); o.User.Claims.Add(("Name", user.Name)!); diff --git a/PyroFetes/Program.cs b/PyroFetes/Program.cs index 262fbb22..e78ef206 100644 --- a/PyroFetes/Program.cs +++ b/PyroFetes/Program.cs @@ -17,7 +17,7 @@ QuestPDF.Settings.License = LicenseType.Community; // On ajoute ici FastEndpoints, un framework REPR et Swagger aux services disponibles dans le projet builder.Services - .AddAuthenticationJwtBearer(s => s.SigningKey = "ThisIsASuperSecretJwtKeyThatIsAtLeast32CharsLong") + .AddAuthenticationJwtBearer(s => s.SigningKey = "v9!Qx7#Lk2@pZ8$wR6!tN5%uF3&cD9^mH1*eY4") .AddAuthorization() .AddFastEndpoints() .SwaggerDocument(options => { options.ShortSchemaNames = true; })