Laravel : Increase time on second time login attem

2020-07-09 07:00发布

问题:

Currently five login attempts blocks user for 1 minute and its working fine with the following code :

if ($this->hasTooManyLoginAttempts($request)) {
    $this->fireLockoutEvent($request);
    return $this->sendLockoutResponse($request);
}

What i want is that, When a user gets unblocked again after the first attempts, On the second attempts the block time should increase to 3 minutes.

I searched around, But could not found anything, Is there any way around it ?

回答1:

I would suggest you try the following code. Please ask if anything is unclear.

$minutes = 3;
$key = $this->throttleKey($request);
$rateLimiter = $this->limiter();

if ($this->hasTooManyLoginAttempts($request)) {

    $attempts = $rateLimiter->attempts($key); 
    if ($attempts > 1) {
        $attempts === 2 && $rateLimiter->clear($key);
        $this->decayMinutes = ($attempts - 1) * $minutes;
        $attempts === 2 && $this->incrementLoginAttempts($request);
        $this->incrementLoginAttempts($request);
    }

    $this->fireLockoutEvent($request);
    return $this->sendLockoutResponse($request);
}

Code for incremental blocking:

$minutes = 3;
$key = $this->throttleKey($request);
$rateLimiter = $this->limiter();

if ($this->hasTooManyLoginAttempts($request)) {

    $attempts = $rateLimiter->attempts($key);
    $rateLimiter->clear($key);
    $this->decayMinutes = $attempts === 1 ? 1 : ($attempts - 1) * $minutes;

    for ($i = 0; $i < $attempts; $i++) {
        $this->incrementLoginAttempts($request);
    }

    $this->fireLockoutEvent($request);
    return $this->sendLockoutResponse($request);
}

Code for incremental blocking with cache:

$minutes = 3;
$key = $this->throttleKey($request);
$rateLimiter = $this->limiter();

if ($this->hasTooManyLoginAttempts($request)) {

    $attempts = $rateLimiter->attempts($key);
    $rateLimiter->clear($key); // might have to add logic here

    $reflection = new \ReflectionClass($rateLimiter);
    $property = $reflection->getProperty('cache');
    $property->setAccessible(true);
    $cache = $property->getValue($rateLimiter);
    $reflectionMethod = new \ReflectionMethod($rateLimiter, 'availableAt');
    $reflectionMethod->setAccessible(true);

    $blockMinutes = $attempts === 1 ? 1 : $attempts > 1 ? ($attempts - 1) * $minutes : 1;
    $cache->add($key.':timer', $reflectionMethod->invoke($rateLimiter, $blockMinutes * 60), $blockMinutes);
    $added = $cache->add($key, 0, $blockMinutes);
    $hits = (int) $cache->increment($key, $attempts);
    if (! $added && $hits === 1) {
        $cache->put($key, 1, $blockMinutes);
    }

    $reflectionMethod->setAccessible(false);
    $property->setAccessible(false);

    $this->fireLockoutEvent($request);
    return $this->sendLockoutResponse($request);
}


回答2:

I think you need to set property in LoginController:

public $decayMinutes = 1; // minutes to lockout

Also you can controll numbers of attempts:

public $maxAttempts = 5;

For more information you can investigate: trait AuthenticatesUsers - which has method "login" and code from your description. And this trait uses another trait: "ThrottlesLogins" -> this traits has method named "decayMinutes". It returns number of minutes.

Hope it will help you!



回答3:

I think laravel default doesn't provide what your need, So you need to save in (cache, session or database) if user had blocked once on your own, and increase decayMinutes as you want.

if ($this->hasTooManyLoginAttempts($request)) {
    if(Cache::has($this->throttleKey($request))){
        $this->decayMinutes = 3;
    }

    Cache::put($this->throttleKey($request), true);
    $this->fireLockoutEvent($request);

    return $this->sendLockoutResponse($request);
}