115 lines
3.3 KiB
C#
115 lines
3.3 KiB
C#
using Microsoft.AspNetCore.Mvc;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using GestorFacturas.API.Data;
|
|
using GestorFacturas.API.Services;
|
|
using GestorFacturas.API.Models;
|
|
|
|
namespace GestorFacturas.API.Controllers;
|
|
|
|
[Route("api/[controller]")]
|
|
[ApiController]
|
|
public class AuthController : ControllerBase
|
|
{
|
|
private readonly ApplicationDbContext _context;
|
|
private readonly AuthService _authService;
|
|
|
|
public AuthController(ApplicationDbContext context, AuthService authService)
|
|
{
|
|
_context = context;
|
|
_authService = authService;
|
|
}
|
|
|
|
[HttpPost("login")]
|
|
public async Task<IActionResult> Login([FromBody] LoginDto login)
|
|
{
|
|
var usuario = await _context.Usuarios.FirstOrDefaultAsync(u => u.Username == login.Username);
|
|
|
|
if (usuario == null || !_authService.VerificarPassword(login.Password, usuario.PasswordHash))
|
|
{
|
|
return Unauthorized(new { mensaje = "Credenciales incorrectas" });
|
|
}
|
|
|
|
// Generar Tokens
|
|
var accessToken = _authService.GenerarAccessToken(usuario);
|
|
|
|
// Pasamos la elección del usuario (true/false)
|
|
var refreshToken = _authService.GenerarRefreshToken(usuario.Id, login.RememberMe);
|
|
|
|
_context.RefreshTokens.Add(refreshToken);
|
|
await _context.SaveChangesAsync();
|
|
|
|
return Ok(new
|
|
{
|
|
token = accessToken,
|
|
refreshToken = refreshToken.Token,
|
|
usuario = usuario.Username
|
|
});
|
|
}
|
|
|
|
[HttpPost("refresh-token")]
|
|
public async Task<IActionResult> RefreshToken([FromBody] RefreshTokenRequest request)
|
|
{
|
|
var oldRefreshToken = await _context.RefreshTokens
|
|
.Include(r => r.Usuario)
|
|
.FirstOrDefaultAsync(r => r.Token == request.Token);
|
|
|
|
if (oldRefreshToken == null || !oldRefreshToken.IsActive)
|
|
{
|
|
return Unauthorized(new { mensaje = "Token inválido" });
|
|
}
|
|
|
|
// Revocar el anterior
|
|
oldRefreshToken.Revoked = DateTime.UtcNow;
|
|
|
|
// Generamos el nuevo token heredando la persistencia del anterior.
|
|
// Si el usuario marcó "Recordarme" hace 20 días, el nuevo token seguirá siendo persistente.
|
|
// Si no lo marcó, seguirá siendo de corta duración.
|
|
var newRefreshToken = _authService.GenerarRefreshToken(oldRefreshToken.UsuarioId, oldRefreshToken.IsPersistent);
|
|
|
|
var newAccessToken = _authService.GenerarAccessToken(oldRefreshToken.Usuario!);
|
|
|
|
_context.RefreshTokens.Add(newRefreshToken);
|
|
await _context.SaveChangesAsync();
|
|
|
|
return Ok(new
|
|
{
|
|
token = newAccessToken,
|
|
refreshToken = newRefreshToken.Token,
|
|
usuario = oldRefreshToken.Usuario!.Username
|
|
});
|
|
}
|
|
|
|
[HttpPost("revoke")]
|
|
public async Task<IActionResult> Revoke([FromBody] RefreshTokenRequest request)
|
|
{
|
|
var token = request.Token;
|
|
|
|
// Buscamos el token en la BD
|
|
var refreshToken = await _context.RefreshTokens
|
|
.FirstOrDefaultAsync(r => r.Token == token);
|
|
|
|
if (refreshToken == null)
|
|
return NotFound(new { mensaje = "Token no encontrado" });
|
|
|
|
// Lo revocamos inmediatamente
|
|
refreshToken.Revoked = DateTime.UtcNow;
|
|
|
|
_context.Update(refreshToken);
|
|
await _context.SaveChangesAsync();
|
|
|
|
return Ok(new { mensaje = "Sesión cerrada correctamente" });
|
|
}
|
|
}
|
|
|
|
// DTOs
|
|
public class LoginDto
|
|
{
|
|
public string Username { get; set; } = string.Empty;
|
|
public string Password { get; set; } = string.Empty;
|
|
public bool RememberMe { get; set; } = false;
|
|
}
|
|
|
|
public class RefreshTokenRequest
|
|
{
|
|
public string Token { get; set; } = string.Empty;
|
|
} |