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:
@@ -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(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user