Limit login attempts by IP address
This commit is contained in:
parent
8e43b185fe
commit
534224c212
|
|
@ -6,6 +6,7 @@ use Log;
|
|||
use Mail;
|
||||
use View;
|
||||
use Utils;
|
||||
use Cache;
|
||||
use Cookie;
|
||||
use Option;
|
||||
use Session;
|
||||
|
|
@ -41,7 +42,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) {
|
||||
if (strtolower($request->input('captcha')) != strtolower(session('phrase')))
|
||||
return json(trans('auth.validation.captcha'), 1);
|
||||
}
|
||||
|
|
@ -50,7 +55,7 @@ class AuthController extends Controller
|
|||
return json(trans('auth.validation.user'), 2);
|
||||
} else {
|
||||
if ($user->verifyPassword($request->input('password'))) {
|
||||
Session::forget('login_fails');
|
||||
Cache::forget($loginFailsCacheKey);
|
||||
|
||||
Session::put('uid' , $user->uid);
|
||||
Session::put('token', $user->getToken());
|
||||
|
|
@ -68,10 +73,11 @@ class AuthController extends Controller
|
|||
->withCookie('uid', $user->uid, $time)
|
||||
->withCookie('token', $user->getToken(), $time);
|
||||
} 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,7 +26,7 @@
|
|||
<span class="glyphicon glyphicon-lock form-control-feedback"></span>
|
||||
</div>
|
||||
|
||||
<div class="row" id="captcha-form" style="{{ (session('login_fails') > 3) ? '' : 'display: none;' }}">
|
||||
<div class="row" id="captcha-form" style="{{ (Cache::get(sha1('login_fails_'.Utils::getClientIp())) > 3) ? '' : 'display: none;' }}">
|
||||
<div class="col-xs-8">
|
||||
<div class="form-group has-feedback">
|
||||
<input id="captcha" type="text" class="form-control" placeholder="{{ trans('auth.captcha') }}">
|
||||
|
|
|
|||
|
|
@ -76,6 +76,8 @@ class AuthControllerTest extends TestCase
|
|||
|
||||
$this->flushSession();
|
||||
|
||||
$loginFailsCacheKey = sha1('login_fails_'.Utils::getClientIp());
|
||||
|
||||
// Logging in should be failed if password is wrong
|
||||
$this->post(
|
||||
'/auth/login', [
|
||||
|
|
@ -87,17 +89,17 @@ 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->flushCache();
|
||||
$this->flushSession();
|
||||
|
||||
// Should check captcha if there are too many fails
|
||||
$this->withSession(
|
||||
[
|
||||
'login_fails' => 4,
|
||||
'phrase' => 'a'
|
||||
]
|
||||
)->post(
|
||||
$this->withCache([
|
||||
$loginFailsCacheKey => 4
|
||||
])->withSession([
|
||||
'phrase' => 'a'
|
||||
])->post(
|
||||
'/auth/login', [
|
||||
'identification' => $user->email,
|
||||
'password' => '12345678',
|
||||
|
|
@ -107,6 +109,7 @@ class AuthControllerTest extends TestCase
|
|||
'msg' => trans('auth.validation.captcha')
|
||||
]);
|
||||
|
||||
$this->flushCache();
|
||||
$this->flushSession();
|
||||
|
||||
// Should return a warning if user isn't existed
|
||||
|
|
@ -121,8 +124,10 @@ class AuthControllerTest extends TestCase
|
|||
|
||||
$this->flushSession();
|
||||
|
||||
// Should clean the `login_fails` session if logged in successfully
|
||||
$this->withSession(['login_fails' => 1])->post('/auth/login', [
|
||||
// Should reset the `login_fails` counter if logged in successfully
|
||||
$this->withCache([
|
||||
$loginFailsCacheKey => 1
|
||||
])->post('/auth/login', [
|
||||
'identification' => $user->email,
|
||||
'password' => '12345678'
|
||||
])->seeJson(
|
||||
|
|
@ -131,8 +136,9 @@ class AuthControllerTest extends TestCase
|
|||
'msg' => trans('auth.login.success'),
|
||||
'token' => $user->getToken()
|
||||
]
|
||||
)->assertSessionMissing('login_fails');
|
||||
)->assertCacheMissing($loginFailsCacheKey);
|
||||
|
||||
$this->flushCache();
|
||||
$this->flushSession();
|
||||
|
||||
// Logged in should be in success if logged in with player name
|
||||
|
|
|
|||
|
|
@ -43,6 +43,49 @@ class TestCase extends Illuminate\Foundation\Testing\TestCase
|
|||
return $this->withSession(['uid' => $role->uid, 'token' => $role->getToken()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
PHPUnit_Framework_Assert::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