using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using System.Security.Claims; using Microsoft.AspNetCore.Authentication; namespace WebApp.Authentication { public class AuthController : Controller { private readonly AuthenticationService _authService; private readonly LoginRateLimitService _rateLimitService; private readonly ILogger _logger; public AuthController( AuthenticationService authService, LoginRateLimitService rateLimitService, ILogger logger) { _authService = authService; _rateLimitService = rateLimitService; _logger = logger; } [HttpPost] [AllowAnonymous] public async Task CookieLogin( [FromForm] string email, [FromForm] string password, [FromForm] bool rememberMe = false) { try { // Get client IP var ipAddress = HttpContext.Connection.RemoteIpAddress?.ToString() ?? "unknown"; // Check rate limiting if (_rateLimitService.IsLockedOut(ipAddress)) { var remaining = _rateLimitService.GetRemainingLockoutTime(ipAddress); _logger.LogWarning( "Login attempt from locked out IP: {IpAddress}. Remaining: {Remaining}", ipAddress, remaining); var errorMsg = Uri.EscapeDataString($"Too many failed attempts. Try again in {remaining?.Minutes ?? 15} minutes."); return Redirect($"/login?error={errorMsg}"); } // Validate credentials var result = _authService.ValidateCredentials(email, password); if (!result.IsSuccess) { // Record failed attempt _rateLimitService.RecordFailedAttempt(ipAddress); _logger.LogWarning( "Failed login attempt for {Email} from {IpAddress}", email, ipAddress); return Redirect("/login?error=Invalid%20email%20or%20password."); } // Success - clear rate limit tracking _rateLimitService.RecordSuccessfulLogin(ipAddress); // Create claims var claims = new List { new Claim(ClaimTypes.Name, result.DisplayName!), new Claim(ClaimTypes.Email, result.Email!), new Claim(ClaimTypes.Role, result.Role!) }; var claimsIdentity = new ClaimsIdentity(claims, "Auth"); var claimsPrincipal = new ClaimsPrincipal(claimsIdentity); // Configure auth properties var authProperties = new AuthenticationProperties { IsPersistent = rememberMe, ExpiresUtc = rememberMe ? DateTimeOffset.UtcNow.AddDays(30) : DateTimeOffset.UtcNow.AddMinutes(20) }; await HttpContext.SignInAsync("Auth", claimsPrincipal, authProperties); _logger.LogInformation( "Successful login for {Email} ({Role}) from {IpAddress}", result.Email, result.Role, ipAddress); return Redirect("/"); } catch (Exception ex) { _logger.LogError(ex, "Error during login process"); TempData["LoginError"] = "An error occurred. Please try again."; return Redirect("/login"); } } [HttpPost] [Authorize] public async Task CookieLogout() { var userEmail = User.FindFirst(ClaimTypes.Email)?.Value; await HttpContext.SignOutAsync("Auth"); _logger.LogInformation("User {Email} logged out", userEmail); return Redirect("/login"); } } }