fixing auth login
This commit is contained in:
parent
4a8072e61b
commit
6ff7e75360
@ -8,45 +8,10 @@ use Illuminate\Http\Response;
|
|||||||
|
|
||||||
class AuthController extends Controller
|
class AuthController extends Controller
|
||||||
{
|
{
|
||||||
private int $captchaTtlSeconds = 120;
|
|
||||||
private int $loginDecaySeconds = 60;
|
private int $loginDecaySeconds = 60;
|
||||||
private int $maxLoginAttempts = 10;
|
private int $maxLoginAttempts = 10;
|
||||||
|
|
||||||
private function generateCaptchaCode(int $length = 6): string
|
|
||||||
{
|
|
||||||
// Avoid ambiguous chars: 0,O,1,I,l
|
|
||||||
$chars = '23456789ABCDEFGHJKLMNPQRSTUVWXYZ';
|
|
||||||
$out = '';
|
|
||||||
$max = strlen($chars) - 1;
|
|
||||||
for ($i = 0; $i < $length; $i++) {
|
|
||||||
$out .= $chars[random_int(0, $max)];
|
|
||||||
}
|
|
||||||
return $out;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function refreshCaptcha(): string
|
|
||||||
{
|
|
||||||
$captcha = $this->generateCaptchaCode(6);
|
|
||||||
session([
|
|
||||||
'login_captcha' => $captcha,
|
|
||||||
'login_captcha_created_at' => now()->getTimestamp(),
|
|
||||||
]);
|
|
||||||
|
|
||||||
return $captcha;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function ensureCaptchaValid(): void
|
|
||||||
{
|
|
||||||
$createdAt = (int) session('login_captcha_created_at', 0);
|
|
||||||
$expired = $createdAt <= 0 || (now()->getTimestamp() - $createdAt) > $this->captchaTtlSeconds;
|
|
||||||
|
|
||||||
if ($expired || (string) session('login_captcha', '') === '') {
|
|
||||||
$this->refreshCaptcha();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function index(){
|
public function index(){
|
||||||
$this->refreshCaptcha();
|
|
||||||
$data = [
|
$data = [
|
||||||
'title' => 'Login Admin | Order Gizi'
|
'title' => 'Login Admin | Order Gizi'
|
||||||
];
|
];
|
||||||
@ -57,7 +22,6 @@ class AuthController extends Controller
|
|||||||
$validated = $request->validate([
|
$validated = $request->validate([
|
||||||
'username' => 'required',
|
'username' => 'required',
|
||||||
'password' => 'required',
|
'password' => 'required',
|
||||||
'captcha' => 'required',
|
|
||||||
'website' => 'nullable',
|
'website' => 'nullable',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@ -69,14 +33,6 @@ class AuthController extends Controller
|
|||||||
$now = time();
|
$now = time();
|
||||||
$rateKey = 'login:' . $request->ip() . ':' . strtolower((string) $request->input('username'));
|
$rateKey = 'login:' . $request->ip() . ':' . strtolower((string) $request->input('username'));
|
||||||
|
|
||||||
|
|
||||||
$this->ensureCaptchaValid();
|
|
||||||
$expectedCaptcha = (string) session('login_captcha', '');
|
|
||||||
$givenCaptcha = strtoupper(preg_replace('/\s+/', '', (string) $request->input('captcha', '')));
|
|
||||||
// One-time use
|
|
||||||
$request->session()->forget('login_captcha');
|
|
||||||
$request->session()->forget('login_captcha_created_at');
|
|
||||||
|
|
||||||
// IMPORTANT: only pass auth credentials to Auth::attempt
|
// IMPORTANT: only pass auth credentials to Auth::attempt
|
||||||
// (do not include captcha / honeypot fields, otherwise Laravel will query non-existent columns)
|
// (do not include captcha / honeypot fields, otherwise Laravel will query non-existent columns)
|
||||||
$credentials = [
|
$credentials = [
|
||||||
@ -89,8 +45,6 @@ class AuthController extends Controller
|
|||||||
return redirect()->intended('/dashboard');
|
return redirect()->intended('/dashboard');
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->refreshCaptcha();
|
|
||||||
|
|
||||||
return back()->with(['alertError' => 'Gagal Login!']);
|
return back()->with(['alertError' => 'Gagal Login!']);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,58 +55,4 @@ class AuthController extends Controller
|
|||||||
request()->session()->regenerateToken();
|
request()->session()->regenerateToken();
|
||||||
return redirect('/login');
|
return redirect('/login');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function captcha(Request $request){
|
|
||||||
$this->ensureCaptchaValid();
|
|
||||||
$captcha = (string) session('login_captcha', '');
|
|
||||||
|
|
||||||
if (!function_exists('imagecreatetruecolor')) {
|
|
||||||
return response('GD extension is not available', Response::HTTP_INTERNAL_SERVER_ERROR)
|
|
||||||
->header('Content-Type', 'text/plain');
|
|
||||||
}
|
|
||||||
|
|
||||||
$width = 140;
|
|
||||||
$height = 44;
|
|
||||||
$img = imagecreatetruecolor($width, $height);
|
|
||||||
|
|
||||||
$bg = imagecolorallocate($img, 245, 247, 250);
|
|
||||||
$fg = imagecolorallocate($img, 35, 45, 70);
|
|
||||||
$noise = imagecolorallocate($img, 120, 130, 150);
|
|
||||||
|
|
||||||
imagefilledrectangle($img, 0, 0, $width, $height, $bg);
|
|
||||||
|
|
||||||
// noise lines
|
|
||||||
for ($i = 0; $i < 6; $i++) {
|
|
||||||
imageline(
|
|
||||||
$img,
|
|
||||||
random_int(0, $width),
|
|
||||||
random_int(0, $height),
|
|
||||||
random_int(0, $width),
|
|
||||||
random_int(0, $height),
|
|
||||||
$noise
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// noise dots
|
|
||||||
for ($i = 0; $i < 180; $i++) {
|
|
||||||
imagesetpixel($img, random_int(0, $width - 1), random_int(0, $height - 1), $noise);
|
|
||||||
}
|
|
||||||
|
|
||||||
// draw text (built-in font to avoid font dependency)
|
|
||||||
$font = 5;
|
|
||||||
$textWidth = imagefontwidth($font) * strlen($captcha);
|
|
||||||
$textHeight = imagefontheight($font);
|
|
||||||
$x = (int) (($width - $textWidth) / 2);
|
|
||||||
$y = (int) (($height - $textHeight) / 2);
|
|
||||||
imagestring($img, $font, $x, $y, $captcha, $fg);
|
|
||||||
|
|
||||||
ob_start();
|
|
||||||
imagepng($img);
|
|
||||||
$png = ob_get_clean();
|
|
||||||
imagedestroy($img);
|
|
||||||
|
|
||||||
return response($png, 200)
|
|
||||||
->header('Content-Type', 'image/png')
|
|
||||||
->header('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -60,9 +60,7 @@
|
|||||||
<p class="mb-4">Please sign-in to your account</p>
|
<p class="mb-4">Please sign-in to your account</p>
|
||||||
@if (session()->has('alertError'))
|
@if (session()->has('alertError'))
|
||||||
<div class="alert alert-danger fw-bold" role="alert">
|
<div class="alert alert-danger fw-bold" role="alert">
|
||||||
@if(session('alertError') === 'captcha')
|
@if(session('alertError') === 'rate')
|
||||||
Captcha salah!
|
|
||||||
@elseif(session('alertError') === 'rate')
|
|
||||||
Terlalu banyak percobaan login. Coba lagi dalam 1 menit.
|
Terlalu banyak percobaan login. Coba lagi dalam 1 menit.
|
||||||
@elseif(session('alertError') === 'backoff')
|
@elseif(session('alertError') === 'backoff')
|
||||||
Mohon tunggu beberapa detik sebelum mencoba lagi.
|
Mohon tunggu beberapa detik sebelum mencoba lagi.
|
||||||
@ -100,20 +98,6 @@
|
|||||||
<span class="input-group-text cursor-pointer"><i class="bx bx-hide"></i></span>
|
<span class="input-group-text cursor-pointer"><i class="bx bx-hide"></i></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-4">
|
|
||||||
<label class="form-label">Captcha</label>
|
|
||||||
<div class="d-flex align-items-center gap-2">
|
|
||||||
<img
|
|
||||||
src="{{ route('captcha.login') }}?t={{ time() }}"
|
|
||||||
alt="captcha"
|
|
||||||
class="border rounded"
|
|
||||||
style="height: 44px; width: 140px; object-fit: cover;"
|
|
||||||
>
|
|
||||||
<input type="text" name="captcha" class="form-control text-uppercase" placeholder="Masukkan kode di gambar" autocomplete="off" required>
|
|
||||||
<a href="/login" class="btn btn-outline-secondary" title="Refresh captcha">Refresh</a>
|
|
||||||
</div>
|
|
||||||
<div class="form-text text-muted">Masukkan kode sesuai yang ditampilkan (huruf tidak membedakan kapital/kecil).</div>
|
|
||||||
</div>
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<button class="btn btn-primary d-grid w-100" type="submit">Login</button>
|
<button class="btn btn-primary d-grid w-100" type="submit">Login</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -22,7 +22,6 @@ use Illuminate\Support\Facades\Route;
|
|||||||
// });
|
// });
|
||||||
Route::get('/login', [AuthController::class, 'index'])->name('login')->middleware('guest');
|
Route::get('/login', [AuthController::class, 'index'])->name('login')->middleware('guest');
|
||||||
Route::post('/login', [AuthController::class, 'authanticate'])->middleware('throttle:login');
|
Route::post('/login', [AuthController::class, 'authanticate'])->middleware('throttle:login');
|
||||||
Route::get('/captcha/login', [AuthController::class, 'captcha'])->name('captcha.login');
|
|
||||||
|
|
||||||
Route::group(['middleware' => ['auth']], function(){
|
Route::group(['middleware' => ['auth']], function(){
|
||||||
Route::group(['prefix' => 'dashboard'], function(){
|
Route::group(['prefix' => 'dashboard'], function(){
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user