Limit login attempts by IP address
This commit is contained in:
parent
bf8ec12645
commit
40deffb3b9
|
|
@ -7,8 +7,7 @@ use Log;
|
|||
use Mail;
|
||||
use View;
|
||||
use Utils;
|
||||
use Cookie;
|
||||
use Option;
|
||||
use Cache;
|
||||
use Session;
|
||||
use App\Events;
|
||||
use App\Models\User;
|
||||
|
|
@ -39,7 +38,11 @@ class AuthController extends Controller
|
|||
// it will return a null value.
|
||||
$user = $users->get($identification, $authType);
|
||||
|
||||
if (session('login_fails', 0) > 3) {
|
||||
// Require CAPTCHA if user fails to login more than 3 times
|
||||
$loginFailsCacheKey = sha1('login_fails_'.Utils::getClientIp());
|
||||
$loginFails = (int) Cache::get($loginFailsCacheKey, 0);
|
||||
|
||||
if ($loginFails > 3) {
|
||||
$this->validate($request, ['captcha' => 'required|captcha']);
|
||||
}
|
||||
|
||||
|
|
@ -53,14 +56,15 @@ class AuthController extends Controller
|
|||
|
||||
event(new Events\UserLoggedIn($user));
|
||||
|
||||
session()->forget('last_requested_path');
|
||||
Cache::forget($loginFailsCacheKey);
|
||||
|
||||
return json(trans('auth.login.success'), 0);
|
||||
} else {
|
||||
Session::put('login_fails', session('login_fails', 0) + 1);
|
||||
// Increase the counter
|
||||
Cache::put($loginFailsCacheKey, ++$loginFails);
|
||||
|
||||
return json(trans('auth.validation.password'), 1, [
|
||||
'login_fails' => session('login_fails')
|
||||
'login_fails' => $loginFails
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,8 +26,9 @@
|
|||
|
||||
<script>
|
||||
Object.defineProperty(window, '__bs_data__', {
|
||||
configurable: false,
|
||||
get: function () {
|
||||
return Object.freeze({ tooManyFails: {{ session('login_fails') > 3 ? 'true' : 'false' }} })
|
||||
return Object.freeze({ tooManyFails: {{ cache(sha1('login_fails_'.Utils::getClientIp())) > 3 ? 'true' : 'false' }} })
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -77,6 +77,8 @@ class AuthControllerTest extends TestCase
|
|||
|
||||
$this->flushSession();
|
||||
|
||||
$loginFailsCacheKey = sha1('login_fails_'.Utils::getClientIp());
|
||||
|
||||
// Logging in should be failed if password is wrong
|
||||
$this->postJson(
|
||||
'/auth/login', [
|
||||
|
|
@ -88,12 +90,12 @@ class AuthControllerTest extends TestCase
|
|||
'msg' => trans('auth.validation.password'),
|
||||
'login_fails' => 1
|
||||
]
|
||||
)->assertSessionHas('login_fails', 1);
|
||||
); // Unable to assert cache content since array driver has unexpected behaviors
|
||||
|
||||
$this->flushSession();
|
||||
|
||||
// Should check captcha if there are too many fails
|
||||
$this->withSession(['login_fails' => 4])
|
||||
$this->withCache([$loginFailsCacheKey => 4])
|
||||
->postJson(
|
||||
'/auth/login', [
|
||||
'identification' => $user->email,
|
||||
|
|
@ -103,6 +105,7 @@ class AuthControllerTest extends TestCase
|
|||
'msg' => trans('validation.required', ['attribute' => 'captcha'])
|
||||
]);
|
||||
|
||||
$this->flushCache();
|
||||
$this->flushSession();
|
||||
|
||||
// Should return a warning if user isn't existed
|
||||
|
|
@ -118,7 +121,8 @@ class AuthControllerTest extends TestCase
|
|||
$this->flushSession();
|
||||
|
||||
// Should clean the `login_fails` session if logged in successfully
|
||||
$this->withSession(['login_fails' => 1])->postJson('/auth/login', [
|
||||
$this->withCache([$loginFailsCacheKey => 1])
|
||||
->postJson('/auth/login', [
|
||||
'identification' => $user->email,
|
||||
'password' => '12345678'
|
||||
])->assertJson(
|
||||
|
|
@ -126,8 +130,10 @@ class AuthControllerTest extends TestCase
|
|||
'errno' => 0,
|
||||
'msg' => trans('auth.login.success')
|
||||
]
|
||||
)->assertSessionMissing('login_fails');
|
||||
);
|
||||
$this->assertCacheMissing($loginFailsCacheKey);
|
||||
|
||||
$this->flushCache();
|
||||
$this->flushSession();
|
||||
|
||||
// Logged in should be in success if logged in with player name
|
||||
|
|
|
|||
|
|
@ -43,6 +43,48 @@ class TestCase extends Illuminate\Foundation\Testing\TestCase
|
|||
return $this->actingAs($role);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the cache to the given array.
|
||||
*
|
||||
* @param array $data
|
||||
* @param int $minutes
|
||||
* @return $this
|
||||
*/
|
||||
public function withCache(array $data, $minutes = 60)
|
||||
{
|
||||
foreach ($data as $key => $value) {
|
||||
$this->app['cache.store']->put($key, $value, $minutes);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the cache does not have a given key.
|
||||
*
|
||||
* @param string|array $key
|
||||
* @return void
|
||||
*/
|
||||
public function assertCacheMissing($key)
|
||||
{
|
||||
if (is_array($key)) {
|
||||
foreach ($key as $k) {
|
||||
$this->assertCacheMissing($k);
|
||||
}
|
||||
} else {
|
||||
$this->assertFalse($this->app['cache.store']->has($key), "Cache has unexpected key: $key");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush all of the current cache data.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function flushCache()
|
||||
{
|
||||
$this->app['cache.store']->flush();
|
||||
}
|
||||
|
||||
protected function tearDown()
|
||||
{
|
||||
$this->beforeApplicationDestroyed(function () {
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user