110 lines
4.5 KiB
PHP
110 lines
4.5 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers;
|
|
|
|
use App\Services\Auth\Contracts\AuthServiceInterface;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\Auth;
|
|
use Illuminate\Support\Facades\Log;
|
|
|
|
class AuthController extends Controller
|
|
{
|
|
public function __construct(
|
|
private AuthServiceInterface $authService
|
|
) {}
|
|
|
|
public function showLoginForm()
|
|
{
|
|
if (Auth::check() && !session('dialog_first_login')) {
|
|
return redirect($this->authService->getRedirectRouteForUser(Auth::user()));
|
|
}
|
|
return view('login');
|
|
}
|
|
|
|
public function login(Request $request)
|
|
{
|
|
// Custom validation check: treat all validation errors as "Invalid email/password"
|
|
$validator = \Illuminate\Support\Facades\Validator::make($request->all(), [
|
|
'mail' => 'required|email|max:255',
|
|
'password' => 'required|string|max:100',
|
|
]);
|
|
|
|
if ($validator->fails()) {
|
|
return back()->withInput($request->only('mail'))->withErrors([
|
|
'mail' => 'Thông tin đăng nhập không đúng. Vui lòng nhập lại',
|
|
]);
|
|
}
|
|
|
|
$credentials = $validator->validated();
|
|
$email = \Illuminate\Support\Str::lower($credentials['mail']);
|
|
$throttleKey = 'login-attempts:' . $email;
|
|
|
|
// Brute-force check (lock after 5 failed attempts)
|
|
if (\Illuminate\Support\Facades\RateLimiter::tooManyAttempts($throttleKey, 5)) {
|
|
Log::warning('Brute-force login attempt blocked', ['email' => $email, 'ip' => $request->ip()]);
|
|
return back()->withInput($request->only('mail'))->with('dialog_error_brute_force', 'Tài khoản của bạn tạm thời bị khóa do nhập sai mật khẩu quá 5 lần. Vui lòng thử lại sau 15 phút.');
|
|
}
|
|
|
|
$result = $this->authService->attemptLogin($credentials, $request);
|
|
|
|
if (!$result['success']) {
|
|
if ($result['error_key'] === 'permission') {
|
|
Log::warning('Login attempt by deactivated user', ['email' => $email, 'ip' => $request->ip()]);
|
|
return back()->withInput($request->only('mail'))->with('dialog_error_permission', $result['error_msg']);
|
|
}
|
|
|
|
// For invalid password / email (counts towards brute-force attempts)
|
|
\Illuminate\Support\Facades\RateLimiter::hit($throttleKey, 900); // 15 minutes lockout
|
|
Log::warning('Failed login attempt', ['email' => $email, 'ip' => $request->ip()]);
|
|
|
|
return back()->withInput($request->only('mail'))->withErrors([
|
|
'mail' => $result['error_msg'],
|
|
]);
|
|
}
|
|
|
|
// Clear rate limiter on success
|
|
\Illuminate\Support\Facades\RateLimiter::clear($throttleKey);
|
|
|
|
$user = $result['user'];
|
|
Log::info('User logged in successfully', ['user_id' => $user->id, 'email' => $user->mail, 'ip' => $request->ip()]);
|
|
|
|
if ($user->role != config('constants.ROLE_ADMIN') && $user->first_login == config('constants.FIRST_LOGIN_TRUE')) {
|
|
return redirect()->route('login')->with('dialog_first_login', true);
|
|
}
|
|
|
|
return redirect($this->authService->getRedirectRouteForUser($user));
|
|
}
|
|
|
|
public function logout(Request $request)
|
|
{
|
|
$userId = Auth::id();
|
|
$this->authService->logout($request);
|
|
Log::info('User logged out', ['user_id' => $userId, 'ip' => $request->ip()]);
|
|
return redirect('/login');
|
|
}
|
|
|
|
public function forgotPassword(Request $request)
|
|
{
|
|
$validator = \Illuminate\Support\Facades\Validator::make($request->all(), [
|
|
'mail' => 'required|email|max:255',
|
|
], [
|
|
'mail.required' => config('constants.MSG_FORGOT_PWD_EMAIL_REQUIRED'),
|
|
'mail.email' => config('constants.MSG_FORGOT_PWD_EMAIL_INVALID'),
|
|
]);
|
|
|
|
if ($validator->fails()) {
|
|
return back()->withInput()->with('dialog_forgot_error', $validator->errors()->first());
|
|
}
|
|
|
|
$result = $this->authService->forgotPassword($request->input('mail'));
|
|
|
|
if (!$result['success']) {
|
|
Log::warning('Forgot password requested for non-existent/invalid email', ['email' => $request->input('mail'), 'ip' => $request->ip()]);
|
|
return back()->withInput()->with('dialog_forgot_error', $result['error_msg']);
|
|
}
|
|
|
|
Log::info('Forgot password requested successfully', ['email' => $request->input('mail'), 'ip' => $request->ip()]);
|
|
return back()->with('dialog_forgot_success', $result['message']);
|
|
}
|
|
}
|