using System.IdentityModel.Tokens.Jwt; using System.Security.Claims; using System.Text; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Options; using Microsoft.IdentityModel.Tokens; using PruebaGentle.Core.Config; using PruebaGentle.Core.DTOs; using PruebaGentle.Core.Interfaces; namespace PruebaGentle.API.Controllers; [ApiController] [Route("api/[controller]")] public class AuthController : ControllerBase { private readonly IUserRepository _userRepository; private readonly IPasswordHasher _passwordHasher; private readonly JwtSettings _jwtSettings; public AuthController( IUserRepository userRepository, IPasswordHasher passwordHasher, IOptions jwtSettings) { _userRepository = userRepository; _passwordHasher = passwordHasher; _jwtSettings = jwtSettings.Value; } [HttpPost("login")] public async Task Login([FromBody] LoginDto dto) { var user = await _userRepository.GetByUsernameAsync(dto.Username); if (user == null) return Unauthorized(new { error = "Credenciales inválidas." }); if (!_passwordHasher.Verify(dto.Password, user.PasswordHash)) return Unauthorized(new { error = "Credenciales inválidas." }); var expiresAt = DateTime.UtcNow.AddHours(_jwtSettings.ExpirationHours); var token = GenerateJwtToken(user.Id, user.Username, user.Email, expiresAt); return Ok(new LoginResponseDto { Token = token, ExpiresAt = expiresAt }); } [HttpPost("register")] public async Task Register([FromBody] RegisterDto dto) { var user = new PruebaGentle.Core.Entities.User { Username = dto.Username, PasswordHash = _passwordHasher.Hash(dto.Password), Email = dto.Email, NombreCompleto = dto.NombreCompleto }; try { var created = await _userRepository.RegisterAsync(user); var expiresAt = DateTime.UtcNow.AddHours(_jwtSettings.ExpirationHours); var token = GenerateJwtToken(created.Id, created.Username, created.Email, expiresAt); return Created(string.Empty, new RegisterResponseDto { Token = token, ExpiresAt = expiresAt, UserId = created.Id }); } catch (Microsoft.Data.SqlClient.SqlException ex) when (ex.Number == 50001) { return Conflict(new { error = "El nombre de usuario ya existe." }); } catch (Microsoft.Data.SqlClient.SqlException ex) when (ex.Number == 50002) { return Conflict(new { error = "El email ya existe." }); } } private string GenerateJwtToken(int userId, string username, string email, DateTime expiresAt) { var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_jwtSettings.Secret)); var credentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256); var claims = new[] { new Claim(JwtRegisteredClaimNames.Sub, userId.ToString()), new Claim(JwtRegisteredClaimNames.UniqueName, username), new Claim(JwtRegisteredClaimNames.Email, email), new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()) }; var token = new JwtSecurityToken( issuer: "PruebaGentle", audience: "PruebaGentle", claims: claims, expires: expiresAt, signingCredentials: credentials); return new JwtSecurityTokenHandler().WriteToken(token); } }