Files
chapter-organizer/WebApp/Authentication/AuthController.cs
T

116 lines
4.1 KiB
C#

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<AuthController> _logger;
public AuthController(
AuthenticationService authService,
LoginRateLimitService rateLimitService,
ILogger<AuthController> logger)
{
_authService = authService;
_rateLimitService = rateLimitService;
_logger = logger;
}
[HttpPost]
[AllowAnonymous]
public async Task<IActionResult> 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<Claim>
{
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<IActionResult> CookieLogout()
{
var userEmail = User.FindFirst(ClaimTypes.Email)?.Value;
await HttpContext.SignOutAsync("Auth");
_logger.LogInformation("User {Email} logged out", userEmail);
return Redirect("/login");
}
}
}