2025-11-20 16:24:40 +09:00
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
namespace App\Http\Controllers\Auth;
|
|
|
|
|
|
|
|
|
|
use App\Http\Controllers\Controller;
|
|
|
|
|
use App\Http\Requests\Auth\LoginRequest;
|
2026-01-20 13:42:28 +09:00
|
|
|
use App\Services\ApiTokenService;
|
2025-11-20 16:24:40 +09:00
|
|
|
use App\Services\AuthService;
|
2026-01-20 13:42:28 +09:00
|
|
|
use Illuminate\Http\JsonResponse;
|
2025-11-20 16:24:40 +09:00
|
|
|
use Illuminate\Http\RedirectResponse;
|
2026-01-20 13:42:28 +09:00
|
|
|
use Illuminate\Support\Facades\Auth;
|
2025-11-20 16:24:40 +09:00
|
|
|
use Illuminate\View\View;
|
|
|
|
|
|
|
|
|
|
class LoginController extends Controller
|
|
|
|
|
{
|
|
|
|
|
public function __construct(
|
2026-01-20 13:42:28 +09:00
|
|
|
private readonly AuthService $authService,
|
|
|
|
|
private readonly ApiTokenService $apiTokenService
|
2025-11-20 16:24:40 +09:00
|
|
|
) {}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 로그인 폼 표시
|
|
|
|
|
*/
|
|
|
|
|
public function showLoginForm(): View
|
|
|
|
|
{
|
|
|
|
|
return view('auth.login');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 로그인 처리
|
2026-01-27 16:49:15 +09:00
|
|
|
* - 이메일 또는 아이디로 로그인 가능
|
|
|
|
|
* - 아이디 로그인은 본사 소속만 허용
|
2025-11-20 16:24:40 +09:00
|
|
|
*/
|
|
|
|
|
public function login(LoginRequest $request): RedirectResponse
|
|
|
|
|
{
|
2026-01-27 16:49:15 +09:00
|
|
|
$credentials = $request->getCredentials();
|
|
|
|
|
$loginField = $request->getLoginField();
|
2026-02-03 10:33:45 +09:00
|
|
|
// Remember Me 항상 활성화 (세션 만료 시 자동 재인증 보장)
|
|
|
|
|
$remember = true;
|
2025-11-20 16:24:40 +09:00
|
|
|
|
2026-01-27 16:49:15 +09:00
|
|
|
if ($this->authService->login($credentials, $remember, $loginField)) {
|
2025-11-20 16:24:40 +09:00
|
|
|
$request->session()->regenerate();
|
|
|
|
|
|
|
|
|
|
return redirect()->intended('/dashboard')
|
|
|
|
|
->with('success', '로그인되었습니다.');
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-30 21:04:32 +09:00
|
|
|
// AuthService에서 설정한 오류 메시지 사용
|
|
|
|
|
$errorMessage = $this->authService->getLoginError()
|
2026-01-27 16:49:15 +09:00
|
|
|
?? '이메일/아이디 또는 비밀번호가 올바르지 않습니다.';
|
2025-11-30 21:04:32 +09:00
|
|
|
|
2025-11-20 16:24:40 +09:00
|
|
|
return back()
|
2026-01-27 16:49:15 +09:00
|
|
|
->withErrors(['login' => $errorMessage])
|
|
|
|
|
->withInput($request->only('login'));
|
2025-11-20 16:24:40 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 로그아웃 처리
|
|
|
|
|
*/
|
|
|
|
|
public function logout(): RedirectResponse
|
|
|
|
|
{
|
|
|
|
|
$this->authService->logout();
|
|
|
|
|
|
|
|
|
|
request()->session()->invalidate();
|
|
|
|
|
request()->session()->regenerateToken();
|
|
|
|
|
|
|
|
|
|
return redirect('/login')
|
|
|
|
|
->with('success', '로그아웃되었습니다.');
|
|
|
|
|
}
|
2026-01-20 13:42:28 +09:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 세션 갱신 (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(),
|
|
|
|
|
]);
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-11-25 11:06:03 +09:00
|
|
|
}
|