From 0f6ba33af3120ec3367111c41e381cb0bb7b6309 Mon Sep 17 00:00:00 2001 From: kjh2064 Date: Wed, 1 Jul 2026 14:24:59 +0900 Subject: [PATCH] fix: stabilize admin login and ci versioning --- .gitea/workflows/deploy.yml | 1 - TaxBaik.Web/Components/Admin/App.razor | 2 +- .../Components/Admin/Pages/Login.razor | 51 ++++++++++++++--- TaxBaik.Web/wwwroot/js/admin-session.js | 55 ------------------- 4 files changed, 43 insertions(+), 66 deletions(-) diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml index 9441974..2ca9a83 100644 --- a/.gitea/workflows/deploy.yml +++ b/.gitea/workflows/deploy.yml @@ -83,7 +83,6 @@ jobs: BUILD_TIME=$(date -u +'%Y-%m-%d %H:%M:%S UTC') mkdir -p ./publish/wwwroot printf '{\n "version": "%s",\n "built": "%s"\n}\n' "$COMMIT_HASH" "$BUILD_TIME" > ./publish/wwwroot/version.json - printf 'Version: %s\nBuilt: %s\n' "$COMMIT_HASH" "$BUILD_TIME" > ./publish/wwwroot/version.txt echo "✓ Build: $COMMIT_HASH @ $BUILD_TIME" - name: Setup SSH diff --git a/TaxBaik.Web/Components/Admin/App.razor b/TaxBaik.Web/Components/Admin/App.razor index 6eebc39..cc1d43d 100644 --- a/TaxBaik.Web/Components/Admin/App.razor +++ b/TaxBaik.Web/Components/Admin/App.razor @@ -34,7 +34,7 @@ - + diff --git a/TaxBaik.Web/Components/Admin/Pages/Login.razor b/TaxBaik.Web/Components/Admin/Pages/Login.razor index a94a505..e05b920 100644 --- a/TaxBaik.Web/Components/Admin/Pages/Login.razor +++ b/TaxBaik.Web/Components/Admin/Pages/Login.razor @@ -1,6 +1,8 @@ @page "/admin/login" @layout TaxBaik.Web.Components.Admin.Layout.BlankLayout @attribute [AllowAnonymous] +@rendermode @(new InteractiveServerRenderMode(prerender: true)) +@inject IApiClient ApiClient @inject ILocalStorageService LocalStorageService @inject IJSRuntime Js @@ -10,23 +12,23 @@ 관리자 로그인 -
+ + + @bind="model.Username" /> + @bind="model.Password" />
- +
@@ -37,12 +39,12 @@ style="width: 100%; min-height: 52px; border: 0; border-radius: 4px; color: white;"> 로그인 - +
@code { - private readonly LoginModel model = new(); + private LoginModel model = new(); private const string RememberedUsernameKey = "admin-remembered-username"; protected override async Task OnInitializedAsync() @@ -64,14 +66,45 @@ protected override async Task OnAfterRenderAsync(bool firstRender) { if (firstRender) - { await Js.InvokeVoidAsync("taxbaikAdminSession.syncRouteClass"); - await Js.InvokeVoidAsync("taxbaikAdminSession.bindLoginForm"); + } + + private async Task HandleLogin() + { + var request = new { model.Username, model.Password }; + var response = await ApiClient.PostAsync("auth/login", request); + + if (response?.AccessToken == null || response?.RefreshToken == null) + { + return; } + + if (model.RememberMe) + { + await LocalStorageService.SetItemAsStringAsync(RememberedUsernameKey, model.Username); + } + else + { + await LocalStorageService.RemoveItemAsync(RememberedUsernameKey); + } + + await Js.InvokeVoidAsync("localStorage.setItem", "accessToken", response.AccessToken); + await Js.InvokeVoidAsync("localStorage.setItem", "refreshToken", response.RefreshToken); + await Js.InvokeVoidAsync("localStorage.setItem", "tokenExpiry", DateTimeOffset.UtcNow.AddSeconds(response.ExpiresIn).ToUnixTimeMilliseconds().ToString()); + await Js.InvokeVoidAsync("window.location.assign", "/taxbaik/admin/dashboard"); } private class LoginModel { public string Username { get; set; } = ""; + public string Password { get; set; } = ""; + public bool RememberMe { get; set; } + } + + private class LoginResponse + { + public string AccessToken { get; set; } = ""; + public string RefreshToken { get; set; } = ""; + public int ExpiresIn { get; set; } } } diff --git a/TaxBaik.Web/wwwroot/js/admin-session.js b/TaxBaik.Web/wwwroot/js/admin-session.js index 7e558a0..154ddf9 100644 --- a/TaxBaik.Web/wwwroot/js/admin-session.js +++ b/TaxBaik.Web/wwwroot/js/admin-session.js @@ -110,61 +110,6 @@ window.taxbaikAdminSession = { new MutationObserver(reloadOnRejectedCircuit) .observe(modal, { attributes: true, attributeFilter: ['class'] }); - }, - - bindLoginForm: function () { - const form = document.getElementById('admin-login-form'); - if (!form || form.dataset.bound === '1') return; - - form.dataset.bound = '1'; - form.addEventListener('submit', async function (event) { - event.preventDefault(); - - const username = form.querySelector('input[placeholder="사용자명"]')?.value?.trim() || ''; - const password = form.querySelector('input[placeholder="비밀번호"]')?.value || ''; - const rememberMe = form.querySelector('input[type="checkbox"]')?.checked || false; - const existing = form.parentElement.querySelector('.login-error-message'); - const submitButton = form.querySelector('button[type="submit"]'); - - if (existing) existing.remove(); - if (submitButton) submitButton.disabled = true; - - try { - const response = await fetch('/taxbaik/api/auth/login', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ username, password }) - }); - - if (!response.ok) { - throw new Error('login failed'); - } - - const data = await response.json(); - if (!data?.accessToken || !data?.refreshToken) { - throw new Error('invalid response'); - } - - localStorage.setItem('accessToken', data.accessToken); - localStorage.setItem('refreshToken', data.refreshToken); - localStorage.setItem('tokenExpiry', String(Date.now() + (data.expiresIn || 3600) * 1000)); - - if (rememberMe) { - localStorage.setItem('admin-remembered-username', username); - } else { - localStorage.removeItem('admin-remembered-username'); - } - - window.location.href = '/taxbaik/admin/dashboard'; - } catch { - const error = document.createElement('div'); - error.className = 'mud-alert mud-alert-filled-error login-error-message mb-4'; - error.textContent = '로그인 중 오류가 발생했습니다.'; - form.parentElement.insertBefore(error, form); - } finally { - if (submitButton) submitButton.disabled = false; - } - }); } };