Files
sam-manage/app/Http/Controllers/Auth/LoginController.php
hskwon 7c0bed7dd9 fix(MNG): HTMX 네비게이션 스크립트 초기화 및 세션 자동 갱신
1. /menus 페이지 hx-boost 네비게이션 시 SortableJS 미실행 수정
   - htmx:afterSettle 이벤트로 페이지별 스크립트 초기화
   - menu-sortable.js로 SortableJS 로직 분리
   - 중복 코드 제거

2. 세션 만료 시 자동 갱신 로직 추가
   - /auth/refresh-session 엔드포인트 추가
   - Remember Token으로 자동 재인증 (자동 로그인 사용자)
   - 재인증 실패 시 로그인 페이지 리다이렉트
2026-01-20 13:42:28 +09:00

154 lines
4.6 KiB
PHP

<?php
namespace App\Http\Controllers\Auth;
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 ApiTokenService $apiTokenService
) {}
/**
* 로그인 폼 표시
*/
public function showLoginForm(): View
{
return view('auth.login');
}
/**
* 로그인 처리
*/
public function login(LoginRequest $request): RedirectResponse
{
$credentials = $request->only('email', 'password');
$remember = $request->boolean('remember', false);
if ($this->authService->login($credentials, $remember)) {
$request->session()->regenerate();
return redirect()->intended('/dashboard')
->with('success', '로그인되었습니다.');
}
// AuthService에서 설정한 오류 메시지 사용
$errorMessage = $this->authService->getLoginError()
?? '이메일 또는 비밀번호가 올바르지 않습니다.';
return back()
->withErrors(['email' => $errorMessage])
->withInput($request->only('email'));
}
/**
* 로그아웃 처리
*/
public function logout(): RedirectResponse
{
$this->authService->logout();
request()->session()->invalidate();
request()->session()->regenerateToken();
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(),
]);
}
}
}