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 @@
관리자 로그인
-
+
@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;
- }
- });
}
};