fix(MNG): HTMX 네비게이션 스크립트 초기화 및 세션 자동 갱신

1. /menus 페이지 hx-boost 네비게이션 시 SortableJS 미실행 수정
   - htmx:afterSettle 이벤트로 페이지별 스크립트 초기화
   - menu-sortable.js로 SortableJS 로직 분리
   - 중복 코드 제거

2. 세션 만료 시 자동 갱신 로직 추가
   - /auth/refresh-session 엔드포인트 추가
   - Remember Token으로 자동 재인증 (자동 로그인 사용자)
   - 재인증 실패 시 로그인 페이지 리다이렉트
This commit is contained in:
2026-01-20 13:42:28 +09:00
parent dff9721d10
commit 7c0bed7dd9
5 changed files with 524 additions and 367 deletions

View File

@@ -4,14 +4,18 @@
use App\Http\Controllers\Controller;
use App\Http\Requests\Auth\LoginRequest;
use App\Services\ApiTokenService;
use App\Services\AuthService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
use Illuminate\Support\Facades\Auth;
use Illuminate\View\View;
class LoginController extends Controller
{
public function __construct(
private readonly AuthService $authService
private readonly AuthService $authService,
private readonly ApiTokenService $apiTokenService
) {}
/**
@@ -59,4 +63,91 @@ public function logout(): RedirectResponse
return redirect('/login')
->with('success', '로그아웃되었습니다.');
}
/**
* 세션 갱신 (Remember Token으로 재인증)
* HTMX 401 에러 시 호출되어 세션을 갱신합니다.
*/
public function refreshSession(): JsonResponse
{
// 이미 인증된 경우 (세션이 아직 유효한 경우)
if (Auth::check()) {
return response()->json([
'success' => true,
'message' => '세션이 유효합니다.',
]);
}
// Remember Token으로 재인증 시도
// Laravel의 Auth::viaRemember()는 remember token 쿠키로 인증 시도
if (Auth::viaRemember()) {
$user = Auth::user();
// HQ 테넌트 소속 확인
if (! $user->belongsToHQ()) {
Auth::logout();
return response()->json([
'success' => false,
'message' => '본사 소속 직원만 접근할 수 있습니다.',
'redirect' => '/login',
], 401);
}
// 활성 상태 확인
if (! $user->is_active) {
Auth::logout();
return response()->json([
'success' => false,
'message' => '비활성화된 계정입니다.',
'redirect' => '/login',
], 401);
}
// HQ 테넌트를 기본 선택
$hqTenant = $user->getHQTenant();
if ($hqTenant) {
session(['selected_tenant_id' => $hqTenant->id]);
// API 토큰 재발급
$this->refreshApiToken($user->id, $hqTenant->id);
}
return response()->json([
'success' => true,
'message' => '세션이 갱신되었습니다.',
]);
}
// Remember Token이 없거나 유효하지 않은 경우
return response()->json([
'success' => false,
'message' => '세션이 만료되었습니다. 다시 로그인해주세요.',
'redirect' => '/login',
], 401);
}
/**
* API 토큰 재발급
*/
private function refreshApiToken(int $userId, int $tenantId): void
{
try {
$result = $this->apiTokenService->exchangeToken($userId, $tenantId);
if ($result['success']) {
$this->apiTokenService->storeTokenInSession(
$result['data']['access_token'],
$result['data']['expires_in']
);
}
} catch (\Exception $e) {
// API 토큰 재발급 실패해도 세션 갱신은 계속 진행
\Log::warning('[LoginController] API token refresh failed', [
'user_id' => $userId,
'error' => $e->getMessage(),
]);
}
}
}