@page "/login"
@using System.ComponentModel.DataAnnotations
@using WebApp.Authentication
@inject NavigationManager Navigation
@inject LoginRateLimitService RateLimitService
@inject IHttpContextAccessor HttpContextAccessor
TSA Chapter Organizer
Sign In
@if (!string.IsNullOrEmpty(_errorMessage))
{
@_errorMessage
}
@if (_isSubmitting)
{
Signing in...
}
else
{
Sign In
}
@code {
private LoginModel _loginModel = new();
private string? _errorMessage;
private bool _isSubmitting = false;
private bool _passwordVisibility;
private InputType _passwordInput = InputType.Password;
private string _passwordInputIcon = Icons.Material.Filled.VisibilityOff;
private class LoginModel
{
[Required(ErrorMessage = "Email is required")]
[EmailAddress(ErrorMessage = "Invalid email format")]
public string Email { get; set; } = string.Empty;
[Required(ErrorMessage = "Password is required")]
[MinLength(8, ErrorMessage = "Password must be at least 8 characters")]
public string Password { get; set; } = string.Empty;
public bool RememberMe { get; set; }
}
private void TogglePasswordVisibility()
{
if (_isSubmitting) return;
_passwordVisibility = !_passwordVisibility;
_passwordInputIcon = _passwordVisibility
? Icons.Material.Filled.Visibility
: Icons.Material.Filled.VisibilityOff;
_passwordInput = _passwordVisibility
? InputType.Text
: InputType.Password;
}
private async Task HandleLogin()
{
_isSubmitting = true;
_errorMessage = null;
try
{
// Get client IP address
var ipAddress = HttpContextAccessor.HttpContext?.Connection.RemoteIpAddress?.ToString()
?? "unknown";
// Check rate limiting
if (RateLimitService.IsLockedOut(ipAddress))
{
var remaining = RateLimitService.GetRemainingLockoutTime(ipAddress);
_errorMessage = $"Too many failed attempts. Please try again in {remaining?.Minutes ?? 15} minutes.";
return;
}
// Navigate to controller endpoint with credentials
var uri = $"/Auth/CookieLogin?email={Uri.EscapeDataString(_loginModel.Email)}" +
$"&password={Uri.EscapeDataString(_loginModel.Password)}" +
$"&rememberMe={_loginModel.RememberMe}";
Navigation.NavigateTo(uri, forceLoad: true);
}
catch (Exception ex)
{
_errorMessage = "An error occurred during login. Please try again.";
Console.WriteLine($"Login error: {ex}");
}
finally
{
_isSubmitting = false;
}
}
}