fix: 배포 후 관리자 세션 복구 처리
TaxBaik CI/CD / build-and-deploy (push) Successful in 56s
TaxBaik Browser E2E / browser-e2e (push) Failing after 3m3s

This commit is contained in:
2026-06-27 21:38:11 +09:00
parent 661ffbbf2c
commit d58e524dfc
6 changed files with 95 additions and 2 deletions
+8
View File
@@ -13,8 +13,16 @@
<component type="typeof(HeadOutlet)" render-mode="InteractiveServer" /> <component type="typeof(HeadOutlet)" render-mode="InteractiveServer" />
</head> </head>
<body> <body>
<div id="components-reconnect-modal" class="admin-reconnect-modal">
<div class="admin-reconnect-card">
<strong>관리자 세션을 다시 연결하고 있습니다.</strong>
<span>배포 또는 서버 재시작 중이면 잠시 후 자동으로 새로고침됩니다.</span>
</div>
</div>
<Routes @rendermode="new InteractiveServerRenderMode(prerender: false)" /> <Routes @rendermode="new InteractiveServerRenderMode(prerender: false)" />
<script src="_content/MudBlazor/MudBlazor.min.js"></script> <script src="_content/MudBlazor/MudBlazor.min.js"></script>
<script src="/taxbaik/js/admin-session.js"></script>
<script src="_framework/blazor.web.js"></script> <script src="_framework/blazor.web.js"></script>
<script>window.taxbaikAdminSession?.watchReconnect();</script>
</body> </body>
</html> </html>
+19 -1
View File
@@ -80,7 +80,7 @@
await ApiClient.SetAuthToken(response.Token); await ApiClient.SetAuthToken(response.Token);
await AuthStateProvider.LoginAsync(response.Token); await AuthStateProvider.LoginAsync(response.Token);
NavigationManager.NavigateTo("/taxbaik/admin/dashboard", forceLoad: false); NavigationManager.NavigateTo(GetReturnUrl(), forceLoad: false);
} }
catch catch
{ {
@@ -100,4 +100,22 @@
public string Username { get; set; } = ""; public string Username { get; set; } = "";
public string Password { get; set; } = ""; public string Password { get; set; } = "";
} }
private string GetReturnUrl()
{
var uri = NavigationManager.ToAbsoluteUri(NavigationManager.Uri);
if (!Microsoft.AspNetCore.WebUtilities.QueryHelpers.ParseQuery(uri.Query).TryGetValue("returnUrl", out var returnUrl)
|| string.IsNullOrWhiteSpace(returnUrl))
{
return "/taxbaik/admin/dashboard";
}
var value = returnUrl.ToString();
if (!value.StartsWith("admin", StringComparison.OrdinalIgnoreCase))
{
return "/taxbaik/admin/dashboard";
}
return $"/taxbaik/{value.TrimStart('/')}";
}
} }
@@ -1,8 +1,13 @@
@inject NavigationManager Navigation @inject NavigationManager Navigation
@inject IJSRuntime Js
@code { @code {
protected override void OnInitialized() protected override async Task OnAfterRenderAsync(bool firstRender)
{ {
if (!firstRender)
return;
await Js.InvokeVoidAsync("taxbaikAdminSession.clearAuthToken");
var returnUrl = Uri.EscapeDataString(Navigation.ToBaseRelativePath(Navigation.Uri)); var returnUrl = Uri.EscapeDataString(Navigation.ToBaseRelativePath(Navigation.Uri));
Navigation.NavigateTo($"/taxbaik/admin/login?returnUrl={returnUrl}", replace: true); Navigation.NavigateTo($"/taxbaik/admin/login?returnUrl={returnUrl}", replace: true);
} }
@@ -6,6 +6,7 @@
@using Microsoft.AspNetCore.Components.Web.Virtualization @using Microsoft.AspNetCore.Components.Web.Virtualization
@using Microsoft.AspNetCore.Components.Authorization @using Microsoft.AspNetCore.Components.Authorization
@using Microsoft.AspNetCore.Authorization @using Microsoft.AspNetCore.Authorization
@using Microsoft.JSInterop
@using MudBlazor @using MudBlazor
@using TaxBaik.Web.Services @using TaxBaik.Web.Services
@using TaxBaik.Domain.Entities @using TaxBaik.Domain.Entities
+35
View File
@@ -169,6 +169,41 @@ button:disabled {
opacity: 0.6; opacity: 0.6;
} }
.admin-reconnect-modal {
display: none;
}
.admin-reconnect-modal.components-reconnect-show,
.admin-reconnect-modal.components-reconnect-failed,
.admin-reconnect-modal.components-reconnect-rejected {
position: fixed;
inset: 0;
z-index: 10000;
display: flex;
align-items: center;
justify-content: center;
padding: 24px;
background: rgba(15, 23, 42, 0.48);
}
.admin-reconnect-card {
width: min(420px, 100%);
padding: 24px;
border-radius: 16px;
background: #fff;
box-shadow: 0 24px 80px rgba(15, 23, 42, 0.28);
}
.admin-reconnect-card strong,
.admin-reconnect-card span {
display: block;
}
.admin-reconnect-card span {
margin-top: 8px;
color: #64748b;
}
/* Responsive */ /* Responsive */
@media (max-width: 600px) { @media (max-width: 600px) {
.mud-container-maxwidth-small { .mud-container-maxwidth-small {
+26
View File
@@ -0,0 +1,26 @@
window.taxbaikAdminSession = {
clearAuthToken: function () {
try {
localStorage.removeItem('auth_token');
} catch {
// Ignore storage errors; redirect still recovers the session.
}
},
watchReconnect: function () {
const modal = document.getElementById('components-reconnect-modal');
if (!modal) {
return;
}
const reloadOnRejectedCircuit = () => {
const className = modal.className || '';
if (className.includes('components-reconnect-failed') ||
className.includes('components-reconnect-rejected')) {
window.setTimeout(() => window.location.reload(), 1500);
}
};
new MutationObserver(reloadOnRejectedCircuit)
.observe(modal, { attributes: true, attributeFilter: ['class'] });
}
};