2025-01-24 19:17:26 -03:00
|
|
|
|
using Microsoft.AspNetCore.Authorization;
|
|
|
|
|
|
using Microsoft.AspNetCore.Identity;
|
|
|
|
|
|
using Microsoft.AspNetCore.Mvc;
|
|
|
|
|
|
using Microsoft.IdentityModel.Tokens;
|
|
|
|
|
|
using System.IdentityModel.Tokens.Jwt;
|
|
|
|
|
|
using System.Security.Claims;
|
|
|
|
|
|
using System.Text;
|
|
|
|
|
|
using phronCare.API.Models;
|
|
|
|
|
|
using Services.Models;
|
|
|
|
|
|
using Services.Interfaces;
|
|
|
|
|
|
using phronCare.API.Models.Authentication.Login;
|
|
|
|
|
|
using phronCare.API.Models.Authentication.SingUp;
|
2025-04-29 18:52:49 -03:00
|
|
|
|
using phronCare.API.Models.Security;
|
2025-01-24 19:17:26 -03:00
|
|
|
|
using Google.Authenticator;
|
|
|
|
|
|
using QRCoder;
|
|
|
|
|
|
using System.ComponentModel.DataAnnotations;
|
|
|
|
|
|
|
|
|
|
|
|
namespace phronCare.API.Controllers
|
|
|
|
|
|
{
|
|
|
|
|
|
[Route("api/[controller]")]
|
|
|
|
|
|
[ApiController]
|
2025-04-29 18:52:49 -03:00
|
|
|
|
public class AuthenticationController(
|
|
|
|
|
|
UserManager<ApplicationUser> userManager,
|
|
|
|
|
|
RoleManager<IdentityRole> roleManager,
|
|
|
|
|
|
IEmailService emailService,
|
|
|
|
|
|
IConfiguration configuration,
|
|
|
|
|
|
SignInManager<ApplicationUser> signInManager,
|
|
|
|
|
|
TwoFactorAuthenticator twoFactorAuthenticator) : ControllerBase
|
2025-01-24 19:17:26 -03:00
|
|
|
|
{
|
|
|
|
|
|
private const int JWT_TOKEN_VALIDITY_HOURS = 48;
|
|
|
|
|
|
|
|
|
|
|
|
#region Declaration Section
|
2025-04-29 18:52:49 -03:00
|
|
|
|
private readonly UserManager<ApplicationUser> userManager = userManager;
|
2025-01-24 19:17:26 -03:00
|
|
|
|
private readonly RoleManager<IdentityRole> roleManager = roleManager;
|
2025-04-29 18:52:49 -03:00
|
|
|
|
private readonly SignInManager<ApplicationUser> signInManager = signInManager;
|
2025-01-24 19:17:26 -03:00
|
|
|
|
private readonly TwoFactorAuthenticator authenticator = twoFactorAuthenticator;
|
|
|
|
|
|
private readonly IEmailService emailService = emailService;
|
|
|
|
|
|
private readonly IConfiguration configuration = configuration;
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
2025-04-29 18:52:49 -03:00
|
|
|
|
#region Security Endpoints
|
|
|
|
|
|
|
2025-01-24 19:17:26 -03:00
|
|
|
|
[HttpPost]
|
|
|
|
|
|
[Route("generate-qr-code")]
|
|
|
|
|
|
public async Task<IActionResult> GenerateQRCodeAsync()
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
2025-04-29 18:52:49 -03:00
|
|
|
|
var user = await signInManager.GetTwoFactorAuthenticationUserAsync();
|
2025-01-24 19:17:26 -03:00
|
|
|
|
if (user == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
return BadRequest(new Response { Status = "Error", Message = "Usuario no autenticado." });
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-04-29 18:52:49 -03:00
|
|
|
|
var setupInfo = authenticator.GenerateSetupCode("MiApp", user.Email, user.Id, false, 10);
|
2025-01-24 19:17:26 -03:00
|
|
|
|
var qrCodeGenerator = new QRCodeGenerator();
|
|
|
|
|
|
var qrCodeData = qrCodeGenerator.CreateQrCode(setupInfo.ManualEntryKey, QRCodeGenerator.ECCLevel.Q);
|
|
|
|
|
|
var qrCode = new PngByteQRCode(qrCodeData);
|
2025-04-29 18:52:49 -03:00
|
|
|
|
var qrCodeImage = qrCode.GetGraphic(10);
|
2025-01-24 19:17:26 -03:00
|
|
|
|
var qrCodeImageData = Convert.ToBase64String(qrCodeImage);
|
|
|
|
|
|
|
|
|
|
|
|
return Ok(new AuthResponse
|
|
|
|
|
|
{
|
|
|
|
|
|
Status = "Success",
|
|
|
|
|
|
Message = "Código QR generado satisfactoriamente.",
|
2025-04-29 18:52:49 -03:00
|
|
|
|
ManualSetupKey = setupInfo.ManualEntryKey,
|
|
|
|
|
|
QRCodeImage = qrCodeImageData
|
2025-01-24 19:17:26 -03:00
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception)
|
|
|
|
|
|
{
|
|
|
|
|
|
return StatusCode(StatusCodes.Status500InternalServerError, new AuthResponse { Status = "Error", Message = "Error al generar el código QR." });
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
[HttpPost]
|
|
|
|
|
|
[Route("register")]
|
|
|
|
|
|
public async Task<IActionResult> Register([FromBody] RegisterUser registerUser)
|
|
|
|
|
|
{
|
|
|
|
|
|
var userExist = await userManager.FindByEmailAsync(registerUser.EmailAddress);
|
|
|
|
|
|
if (userExist != null)
|
2025-04-29 18:52:49 -03:00
|
|
|
|
return StatusCode(StatusCodes.Status409Conflict, "El correo ingresado ya está en uso.");
|
|
|
|
|
|
|
2025-01-24 19:17:26 -03:00
|
|
|
|
userExist = await userManager.FindByNameAsync(registerUser.UserName);
|
|
|
|
|
|
if (userExist != null)
|
|
|
|
|
|
return StatusCode(StatusCodes.Status409Conflict, "El usuario ingresado ya existe.");
|
|
|
|
|
|
|
2025-04-29 18:52:49 -03:00
|
|
|
|
var user = new ApplicationUser
|
2025-01-24 19:17:26 -03:00
|
|
|
|
{
|
|
|
|
|
|
Email = registerUser.EmailAddress,
|
2025-04-29 18:52:49 -03:00
|
|
|
|
UserName = registerUser.UserName,
|
2025-01-24 19:17:26 -03:00
|
|
|
|
SecurityStamp = Guid.NewGuid().ToString(),
|
2025-04-29 18:52:49 -03:00
|
|
|
|
FirstName = registerUser.FirstName,
|
|
|
|
|
|
LastName = registerUser.LastName,
|
|
|
|
|
|
Address = registerUser.Address,
|
|
|
|
|
|
Department = registerUser.Department,
|
|
|
|
|
|
CompanyName = registerUser.CompanyName,
|
|
|
|
|
|
BirthDate = registerUser.BirthDate
|
2025-01-24 19:17:26 -03:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
if (await roleManager.RoleExistsAsync(registerUser.Role))
|
|
|
|
|
|
{
|
|
|
|
|
|
var result = await userManager.CreateAsync(user, registerUser.Password);
|
|
|
|
|
|
if (!result.Succeeded)
|
|
|
|
|
|
{
|
2025-04-29 18:52:49 -03:00
|
|
|
|
return StatusCode(StatusCodes.Status500InternalServerError, $"Creación de usuario fallida: {string.Join(", ", result.Errors.Select(e => e.Description))}");
|
2025-01-24 19:17:26 -03:00
|
|
|
|
}
|
2025-04-29 18:52:49 -03:00
|
|
|
|
|
2025-01-24 19:17:26 -03:00
|
|
|
|
await userManager.AddToRoleAsync(user, registerUser.Role);
|
|
|
|
|
|
|
|
|
|
|
|
var token = await userManager.GenerateEmailConfirmationTokenAsync(user);
|
|
|
|
|
|
var confirmationLink = Url.Action(nameof(ConfirmEmail), "Authentication", new { token, email = user.Email }, Request.Scheme);
|
2025-04-29 18:52:49 -03:00
|
|
|
|
var message = new Message(new[] { user.Email! }, "phronCare - Link de verificación", confirmationLink!);
|
2025-01-24 19:17:26 -03:00
|
|
|
|
emailService.SendEmail(message);
|
|
|
|
|
|
|
2025-04-29 18:52:49 -03:00
|
|
|
|
return StatusCode(StatusCodes.Status201Created, $"Usuario creado satisfactoriamente. Debe autenticar la cuenta desde su correo: {user.Email}");
|
2025-01-24 19:17:26 -03:00
|
|
|
|
}
|
2025-04-29 18:52:49 -03:00
|
|
|
|
|
|
|
|
|
|
return StatusCode(StatusCodes.Status500InternalServerError, "El rol no existe. ¡Inténtalo nuevamente!");
|
2025-01-24 19:17:26 -03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
[HttpGet("confirmemail")]
|
|
|
|
|
|
public async Task<IActionResult> ConfirmEmail(string token, string email)
|
|
|
|
|
|
{
|
|
|
|
|
|
var user = await userManager.FindByEmailAsync(email);
|
|
|
|
|
|
if (user != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
var result = await userManager.ConfirmEmailAsync(user, token);
|
|
|
|
|
|
if (result.Succeeded)
|
2025-04-29 18:52:49 -03:00
|
|
|
|
return Ok(new Response { Status = "Success", Message = "Email verificado satisfactoriamente." });
|
2025-01-24 19:17:26 -03:00
|
|
|
|
}
|
2025-04-29 18:52:49 -03:00
|
|
|
|
return Conflict(new Response { Status = "Error", Message = "Este usuario no existe." });
|
2025-01-24 19:17:26 -03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
[HttpPost]
|
|
|
|
|
|
[Route("login")]
|
|
|
|
|
|
public async Task<IActionResult> Login([FromBody] LoginModel loginModel)
|
|
|
|
|
|
{
|
|
|
|
|
|
await signInManager.SignOutAsync();
|
|
|
|
|
|
var user = await userManager.FindByNameAsync(loginModel.Username);
|
|
|
|
|
|
if (user is null)
|
2025-04-29 18:52:49 -03:00
|
|
|
|
return Unauthorized("El nombre de usuario o contraseña son incorrectos.");
|
2025-01-24 19:17:26 -03:00
|
|
|
|
|
|
|
|
|
|
var canSignIn = await signInManager.CanSignInAsync(user);
|
|
|
|
|
|
if (!canSignIn)
|
|
|
|
|
|
{
|
|
|
|
|
|
string message = string.Empty;
|
|
|
|
|
|
if (userManager.Options.SignIn.RequireConfirmedEmail && !(await userManager.IsEmailConfirmedAsync(user)))
|
|
|
|
|
|
{
|
2025-04-29 18:52:49 -03:00
|
|
|
|
message = $"El usuario {user.UserName} no puede iniciar sesión sin tener el email confirmado.";
|
2025-01-24 19:17:26 -03:00
|
|
|
|
}
|
|
|
|
|
|
if (userManager.Options.SignIn.RequireConfirmedPhoneNumber && !(await userManager.IsPhoneNumberConfirmedAsync(user)))
|
|
|
|
|
|
{
|
2025-04-29 18:52:49 -03:00
|
|
|
|
message = $"El usuario {user.UserName} no puede iniciar sesión sin tener confirmado el número de teléfono.";
|
2025-01-24 19:17:26 -03:00
|
|
|
|
}
|
2025-04-29 18:52:49 -03:00
|
|
|
|
return Unauthorized(message);
|
2025-01-24 19:17:26 -03:00
|
|
|
|
}
|
2025-04-29 18:52:49 -03:00
|
|
|
|
|
|
|
|
|
|
if (await userManager.CheckPasswordAsync(user, loginModel.Password))
|
2025-01-24 19:17:26 -03:00
|
|
|
|
{
|
|
|
|
|
|
if (!user.TwoFactorEnabled)
|
|
|
|
|
|
return await GenerateAccess(user);
|
2025-04-29 18:52:49 -03:00
|
|
|
|
|
|
|
|
|
|
return Accepted(new Response { Status = "Success", Message = $"Debe ingresar el código desde la app Google Authenticator: {user.UserName}" });
|
2025-01-24 19:17:26 -03:00
|
|
|
|
}
|
2025-04-29 18:52:49 -03:00
|
|
|
|
|
|
|
|
|
|
return Unauthorized("El nombre de usuario o contraseña son incorrectos.");
|
2025-01-24 19:17:26 -03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
[HttpPost]
|
|
|
|
|
|
[Route("login-2FA")]
|
|
|
|
|
|
public async Task<IActionResult> LoginWithOTP(string code, string username)
|
|
|
|
|
|
{
|
|
|
|
|
|
var user = await userManager.FindByNameAsync(username);
|
|
|
|
|
|
if (user is not null)
|
|
|
|
|
|
{
|
2025-04-29 18:52:49 -03:00
|
|
|
|
bool validate = authenticator.ValidateTwoFactorPIN(user.Id, code);
|
2025-01-24 19:17:26 -03:00
|
|
|
|
if (validate)
|
|
|
|
|
|
return await GenerateAccess(user);
|
|
|
|
|
|
}
|
2025-04-29 18:52:49 -03:00
|
|
|
|
return Unauthorized(new Response { Status = "Error", Message = "Código de verificación incorrecto." });
|
2025-01-24 19:17:26 -03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
[HttpPost]
|
|
|
|
|
|
[AllowAnonymous]
|
|
|
|
|
|
[Route("forgot-password")]
|
2025-04-29 18:52:49 -03:00
|
|
|
|
public async Task<IActionResult> ForgotPassword([Required] string email)
|
2025-01-24 19:17:26 -03:00
|
|
|
|
{
|
|
|
|
|
|
var user = await userManager.FindByEmailAsync(email);
|
|
|
|
|
|
if (user != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
var token = await userManager.GeneratePasswordResetTokenAsync(user);
|
|
|
|
|
|
var forgotPasswordLink = Url.Action(nameof(ResetPassword), "Authentication", new { token, email = user.Email }, Request.Scheme);
|
|
|
|
|
|
|
2025-04-29 18:52:49 -03:00
|
|
|
|
var message = new Message(new[] { user.Email! }, "phronCare - Enlace de recuperación de contraseña", forgotPasswordLink!);
|
2025-01-24 19:17:26 -03:00
|
|
|
|
emailService.SendEmail(message);
|
2025-04-29 18:52:49 -03:00
|
|
|
|
return Ok($"La solicitud de cambio de contraseña se envió a: {user.Email} exitosamente.");
|
2025-01-24 19:17:26 -03:00
|
|
|
|
}
|
2025-04-29 18:52:49 -03:00
|
|
|
|
return BadRequest("No se pudo enviar el enlace al correo, por favor intente nuevamente.");
|
2025-01-24 19:17:26 -03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
[HttpGet("reset-password")]
|
2025-04-29 18:52:49 -03:00
|
|
|
|
public IActionResult ResetPassword(string token, string email)
|
2025-01-24 19:17:26 -03:00
|
|
|
|
{
|
2025-04-29 18:52:49 -03:00
|
|
|
|
var htmlContent = GetResetPasswordHtmlContent(email, token);
|
2025-01-24 19:17:26 -03:00
|
|
|
|
var bytes = Encoding.UTF8.GetBytes(htmlContent);
|
|
|
|
|
|
var stream = new MemoryStream(bytes);
|
|
|
|
|
|
return File(stream, "text/html");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
[HttpPost]
|
|
|
|
|
|
[AllowAnonymous]
|
|
|
|
|
|
[Route("reset-password")]
|
|
|
|
|
|
public async Task<IActionResult> ResetPassword([FromBody] ResetPassword resetPassword)
|
|
|
|
|
|
{
|
|
|
|
|
|
var user = await userManager.FindByEmailAsync(resetPassword.Email);
|
|
|
|
|
|
if (user != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
var resetPassResult = await userManager.ResetPasswordAsync(user, resetPassword.Token, resetPassword.Password);
|
|
|
|
|
|
if (!resetPassResult.Succeeded)
|
|
|
|
|
|
{
|
|
|
|
|
|
return StatusCode(StatusCodes.Status500InternalServerError, resetPassResult.Errors.First().Description);
|
|
|
|
|
|
}
|
2025-04-29 18:52:49 -03:00
|
|
|
|
return Ok("La contraseña ha sido cambiada correctamente.");
|
2025-01-24 19:17:26 -03:00
|
|
|
|
}
|
2025-04-29 18:52:49 -03:00
|
|
|
|
return StatusCode(StatusCodes.Status500InternalServerError, "No se pudo encontrar el usuario, por favor intente nuevamente.");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static string GetResetPasswordHtmlContent(string username, string token)
|
|
|
|
|
|
{
|
|
|
|
|
|
return @$"
|
|
|
|
|
|
<!DOCTYPE html>
|
|
|
|
|
|
<html>
|
|
|
|
|
|
<head><meta charset='UTF-8'><meta name='viewport' content='width=device-width, initial-scale=1.0'>
|
|
|
|
|
|
<title>phronCare - Notificación</title></head>
|
|
|
|
|
|
<body><h2>Usuario: {username}</h2><h3>Token: {token}</h3></body>
|
|
|
|
|
|
</html>";
|
2025-01-24 19:17:26 -03:00
|
|
|
|
}
|
2025-03-22 01:19:48 -03:00
|
|
|
|
#endregion
|
2025-04-29 18:52:49 -03:00
|
|
|
|
|
2025-01-24 19:17:26 -03:00
|
|
|
|
#region GenerateAccess
|
2025-04-29 18:52:49 -03:00
|
|
|
|
//private async Task<IActionResult> GenerateAccess(ApplicationUser user)
|
|
|
|
|
|
//{
|
|
|
|
|
|
// try
|
|
|
|
|
|
// {
|
|
|
|
|
|
// var authClaims = new List<Claim>
|
|
|
|
|
|
// {
|
|
|
|
|
|
// new(ClaimTypes.Name, user.UserName),
|
|
|
|
|
|
// new(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
|
|
|
|
|
|
// };
|
|
|
|
|
|
|
|
|
|
|
|
// var userRoles = await userManager.GetRolesAsync(user);
|
|
|
|
|
|
// foreach (var role in userRoles)
|
|
|
|
|
|
// {
|
|
|
|
|
|
// authClaims.Add(new Claim(ClaimTypes.Role, role));
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
// var jwtToken = GetToken(authClaims);
|
|
|
|
|
|
|
|
|
|
|
|
// var userSession = new UserSession
|
|
|
|
|
|
// {
|
|
|
|
|
|
// UserName = user.UserName,
|
|
|
|
|
|
// Role = userRoles.First(),
|
|
|
|
|
|
// Token = new JwtSecurityTokenHandler().WriteToken(jwtToken),
|
|
|
|
|
|
// ExpiresIn = (int)jwtToken.ValidTo.Subtract(DateTime.Now).TotalSeconds,
|
|
|
|
|
|
// ExpiryTimeStamp = jwtToken.ValidTo
|
|
|
|
|
|
// };
|
|
|
|
|
|
|
|
|
|
|
|
// return Ok(userSession);
|
|
|
|
|
|
// }
|
|
|
|
|
|
// catch (Exception ex)
|
|
|
|
|
|
// {
|
|
|
|
|
|
// return BadRequest(ex.Message);
|
|
|
|
|
|
// }
|
|
|
|
|
|
//}
|
|
|
|
|
|
private async Task<IActionResult> GenerateAccess(ApplicationUser user)
|
2025-01-24 19:17:26 -03:00
|
|
|
|
{
|
2025-04-29 18:52:49 -03:00
|
|
|
|
try
|
2025-01-24 19:17:26 -03:00
|
|
|
|
{
|
2025-04-29 18:52:49 -03:00
|
|
|
|
var authClaims = new List<Claim>
|
|
|
|
|
|
{
|
|
|
|
|
|
new(ClaimTypes.Name, user.UserName),
|
|
|
|
|
|
new(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
var userRoles = await userManager.GetRolesAsync(user);
|
|
|
|
|
|
|
|
|
|
|
|
if (!userRoles.Any())
|
|
|
|
|
|
{
|
|
|
|
|
|
return BadRequest("El usuario no tiene ningún rol asignado. Verifica el proceso de registro.");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
foreach (var role in userRoles)
|
|
|
|
|
|
{
|
|
|
|
|
|
authClaims.Add(new Claim(ClaimTypes.Role, role));
|
|
|
|
|
|
}
|
2025-04-29 09:26:01 -03:00
|
|
|
|
|
2025-04-29 18:52:49 -03:00
|
|
|
|
var jwtToken = GetToken(authClaims);
|
2025-04-29 09:26:01 -03:00
|
|
|
|
|
2025-04-29 18:52:49 -03:00
|
|
|
|
var userSession = new UserSession
|
|
|
|
|
|
{
|
|
|
|
|
|
UserName = user.UserName,
|
|
|
|
|
|
Role = userRoles.First(), // ya validado que hay al menos uno
|
|
|
|
|
|
Token = new JwtSecurityTokenHandler().WriteToken(jwtToken),
|
|
|
|
|
|
ExpiresIn = (int)jwtToken.ValidTo.Subtract(DateTime.Now).TotalSeconds,
|
|
|
|
|
|
ExpiryTimeStamp = jwtToken.ValidTo
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
return Ok(userSession);
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
2025-01-24 19:17:26 -03:00
|
|
|
|
{
|
2025-04-29 18:52:49 -03:00
|
|
|
|
// O podés loguearlo con logger si querés
|
|
|
|
|
|
return StatusCode(StatusCodes.Status500InternalServerError, $"Error generando token: {ex.Message}");
|
|
|
|
|
|
}
|
2025-01-24 19:17:26 -03:00
|
|
|
|
}
|
2025-04-29 18:52:49 -03:00
|
|
|
|
|
2025-01-24 19:17:26 -03:00
|
|
|
|
public class UserSession
|
|
|
|
|
|
{
|
|
|
|
|
|
public string UserName { get; set; }
|
|
|
|
|
|
public string Token { get; set; }
|
|
|
|
|
|
public string Role { get; set; }
|
|
|
|
|
|
public int ExpiresIn { get; set; }
|
|
|
|
|
|
public DateTime ExpiryTimeStamp { get; set; }
|
|
|
|
|
|
}
|
|
|
|
|
|
#endregion
|
2025-04-29 18:52:49 -03:00
|
|
|
|
|
2025-01-24 19:17:26 -03:00
|
|
|
|
#region GenerateToken
|
|
|
|
|
|
private JwtSecurityToken GetToken(List<Claim> authClaims)
|
|
|
|
|
|
{
|
2025-04-28 19:33:43 -03:00
|
|
|
|
var secret = configuration["JWT:Secret"];
|
|
|
|
|
|
if (string.IsNullOrWhiteSpace(secret))
|
|
|
|
|
|
throw new InvalidOperationException("El Secret no está configurado.");
|
|
|
|
|
|
|
2025-04-29 18:52:49 -03:00
|
|
|
|
var authSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secret));
|
2025-04-28 19:33:43 -03:00
|
|
|
|
var credentials = new SigningCredentials(authSigningKey, SecurityAlgorithms.HmacSha256);
|
|
|
|
|
|
|
2025-04-29 18:52:49 -03:00
|
|
|
|
return new JwtSecurityToken(
|
2025-01-24 19:17:26 -03:00
|
|
|
|
issuer: configuration["JWT:ValidIssuer"],
|
|
|
|
|
|
audience: configuration["JWT:ValidAudience"],
|
2025-04-28 19:33:43 -03:00
|
|
|
|
expires: DateTime.UtcNow.AddHours(JWT_TOKEN_VALIDITY_HOURS),
|
2025-01-24 19:17:26 -03:00
|
|
|
|
claims: authClaims,
|
2025-04-28 19:33:43 -03:00
|
|
|
|
signingCredentials: credentials
|
2025-01-24 19:17:26 -03:00
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
}
|
2025-04-29 18:52:49 -03:00
|
|
|
|
}
|