@page "/login" @attribute [AllowAnonymous] @layout AuthLayout @inject AuthenticationStateProvider AuthStateProvider @inject NavigationManager NavigationManager @inject HttpClient Http 로그인 - QuantEngine Q QuantEngine 은퇴자산포트폴리오 투자 관리 시스템 @if (!string.IsNullOrEmpty(ErrorMessage)) { @ErrorMessage } @(IsSubmitting ? "인증 중..." : "로그인") @code { private string Username { get; set; } = string.Empty; private string Password { get; set; } = string.Empty; private string ErrorMessage { get; set; } = string.Empty; private bool IsSubmitting { get; set; } = false; private bool RememberUsername { get; set; } = true; protected override async Task OnInitializedAsync() { var customProvider = (CustomAuthenticationStateProvider)AuthStateProvider; var remembered = await customProvider.GetRememberedUsernameAsync(); if (!string.IsNullOrWhiteSpace(remembered)) { Username = remembered; RememberUsername = true; } } private sealed class LoginResponse { public bool Success { get; set; } public string? Username { get; set; } public string? Role { get; set; } public string? AccessToken { get; set; } public string? ExpiresAt { get; set; } } private async Task HandleLoginAsync() { ErrorMessage = string.Empty; if (string.IsNullOrWhiteSpace(Username) || string.IsNullOrWhiteSpace(Password)) { ErrorMessage = "아이디와 비밀번호를 모두 입력해 주세요."; return; } IsSubmitting = true; try { var response = await Http.PostAsJsonAsync("api/auth/login", new { Username, Password }); if (response.IsSuccessStatusCode) { var auth = await response.Content.ReadFromJsonAsync(); if (auth is null || string.IsNullOrWhiteSpace(auth.AccessToken)) { ErrorMessage = "로그인 응답이 유효하지 않습니다."; return; } var customProvider = (CustomAuthenticationStateProvider)AuthStateProvider; await customProvider.MarkUserAsAuthenticatedAsync(auth.Username ?? Username, auth.AccessToken, auth.Role ?? "Admin", RememberUsername); NavigationManager.NavigateTo("/dashboard"); } else { ErrorMessage = "아이디 또는 비밀번호가 올바르지 않습니다."; } } catch (Exception ex) { ErrorMessage = $"로그인 중 오류가 발생했습니다: {ex.Message}"; } finally { IsSubmitting = false; } } }