Mix v6 & use RateLimiter Facade vs. trait

This commit is contained in:
Ryan Scherler
2020-12-20 14:01:32 -08:00
parent 22a5f2ee09
commit dc3558a2ac
12 changed files with 4641 additions and 4338 deletions
+8 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+2 -4
View File
@@ -1,6 +1,4 @@
{
"/js/filament.js": "/js/filament.js?id=9995e728ce8648b81f5d",
"/css/filament.css": "/css/filament.css?id=93f842bce37befef5606",
"/js/filament.js.map": "/js/filament.js.map?id=1d3615b89069bfd79261",
"/css/filament.css.map": "/css/filament.css.map?id=2d1bc71ec284f1c1be4a"
"/js/filament.js": "/js/filament.js?id=575bb8a26dd76080eafa",
"/css/filament.css": "/css/filament.css?id=ea771d027184eb0863c0"
}
+4558 -4170
View File
File diff suppressed because it is too large Load Diff
+14 -15
View File
@@ -1,11 +1,11 @@
{
"name": "filament",
"scripts": {
"dev": "npm run development",
"development": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
"watch": "npm run development -- --watch",
"prod": "npm run production",
"production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --no-progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
"dev": "mix",
"watch": "mix watch",
"watch-poll": "mix watch -- --watch-options-poll=1000",
"hot": "mix watch --hot",
"prod": "mix --production",
"start": "npm run watch"
},
"author": {
@@ -14,24 +14,23 @@
},
"license": "MIT",
"dependencies": {
"@popperjs/core": "^2.5.4",
"alpinejs": "^2.7.3",
"@popperjs/core": "^2.6.0",
"alpinejs": "^2.8.0",
"focus-visible": "^5.2.0"
},
"devDependencies": {
"@tailwindcss/forms": "^0.2.1",
"@tailwindcss/typography": "^0.3.1",
"autoprefixer": "^9.8.6",
"browser-sync": "^2.26.13",
"browser-sync-webpack-plugin": "^2.2.2",
"cross-env": "^7.0.2",
"cross-env": "^7.0.3",
"dotenv": "^8.2.0",
"laravel-mix": "^5.0.9",
"postcss-import": "^12.0.1",
"postcss-nested": "^4.2.3",
"prettier": "^2.2.0",
"tailwindcss": "npm:@tailwindcss/postcss7-compat@^2.0.1",
"vue-template-compiler": "^2.6.12"
"laravel-mix": "^6.0.0",
"postcss": "^8.2.1",
"postcss-import": "^14.0.0",
"postcss-nested": "^5.0.3",
"prettier": "^2.2.1",
"tailwindcss": "^2.0.2"
},
"optionalDependencies": {
"fsevents": "^2.2.1"
+7
View File
@@ -0,0 +1,7 @@
module.exports = {
plugins: [
require('postcss-import'),
require('tailwindcss'),
require('postcss-nested'),
],
}
+46 -12
View File
@@ -2,14 +2,17 @@
namespace Filament\Http\Livewire\Auth;
use Livewire\Component;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\{
RateLimiter,
Auth,
Route,
};
use Illuminate\Validation\ValidationException;
use Illuminate\Auth\Events\Lockout;
use Livewire\Component;
use Filament\Facades\Filament;
use Filament\Traits\ThrottlesLogins;
use Filament\Fields\{
Text,
Checkbox,
@@ -17,8 +20,6 @@ use Filament\Fields\{
class Login extends Component
{
use ThrottlesLogins;
public $message;
public $email;
public $password;
@@ -79,21 +80,19 @@ class Login extends Component
*/
public function submit(Request $request)
{
$this->ensureIsNotRateLimited($request);
$data = $this->validate();
if ($this->hasTooManyLoginAttempts($request)) {
$this->fireLockoutEvent($request);
return $this->sendLockoutResponse($request);
}
if (Auth::attempt($data, (bool) $this->remember)) {
RateLimiter::clear($this->throttleKey());
return redirect()->intended(Filament::home());
}
$this->incrementLoginAttempts($request);
RateLimiter::hit($this->throttleKey());
$this->addError('password', __('auth.failed'));
$this->addError('email', __('auth.failed'));
}
public function render(): \Illuminate\View\View
@@ -101,4 +100,39 @@ class Login extends Component
return view('filament::livewire.auth.login')
->layout('filament::layouts.auth', ['title' => __('filament::auth.signin')]);
}
/**
* Ensure the login request is not rate limited.
*
* @return void
*
* @throws \Illuminate\Validation\ValidationException
*/
protected function ensureIsNotRateLimited(Request $request)
{
if (! RateLimiter::tooManyAttempts($this->throttleKey(), 5)) {
return;
}
event(new Lockout($request));
$seconds = RateLimiter::availableIn($this->throttleKey());
throw ValidationException::withMessages([
'email' => trans('auth.throttle', [
'seconds' => $seconds,
'minutes' => ceil($seconds / 60),
]),
]);
}
/**
* Get the rate limiting throttle key for the request.
*
* @return string
*/
protected function throttleKey()
{
return Str::lower($this->email.'|'.request()->ip());
}
}
-125
View File
@@ -1,125 +0,0 @@
<?php
namespace Filament\Traits;
use Illuminate\Auth\Events\Lockout;
use Illuminate\Cache\RateLimiter;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Lang;
use Illuminate\Support\Str;
use Illuminate\Validation\ValidationException;
trait ThrottlesLogins
{
/**
* Determine if the user has too many failed login attempts.
*
* @param \Illuminate\Http\Request $request
* @return bool
*/
protected function hasTooManyLoginAttempts(Request $request)
{
return $this->limiter()->tooManyAttempts(
$this->throttleKey($request), $this->maxAttempts()
);
}
/**
* Increment the login attempts for the user.
*
* @param \Illuminate\Http\Request $request
* @return void
*/
protected function incrementLoginAttempts(Request $request)
{
$this->limiter()->hit(
$this->throttleKey($request), $this->decayMinutes() * 60
);
}
/**
* Redirect the user after determining they are locked out.
*
* @param \Illuminate\Http\Request $request
* @return void
*
* @throws \Illuminate\Validation\ValidationException
*/
protected function sendLockoutResponse(Request $request)
{
$seconds = $this->limiter()->availableIn(
$this->throttleKey($request)
);
throw ValidationException::withMessages([
'email' => [Lang::get('auth.throttle', [
'seconds' => $seconds,
'minutes' => ceil($seconds / 60),
])],
])->status(Response::HTTP_TOO_MANY_REQUESTS);
}
/**
* Clear the login locks for the given user credentials.
*
* @param \Illuminate\Http\Request $request
* @return void
*/
protected function clearLoginAttempts(Request $request)
{
$this->limiter()->clear($this->throttleKey($request));
}
/**
* Fire an event when a lockout occurs.
*
* @param \Illuminate\Http\Request $request
* @return void
*/
protected function fireLockoutEvent(Request $request)
{
event(new Lockout($request));
}
/**
* Get the throttle key for the given request.
*
* @param \Illuminate\Http\Request $request
* @return string
*/
protected function throttleKey(Request $request)
{
return Str::lower($request->input('email')).'|'.$request->ip();
}
/**
* Get the rate limiter instance.
*
* @return \Illuminate\Cache\RateLimiter
*/
protected function limiter()
{
return app(RateLimiter::class);
}
/**
* Get the maximum number of attempts to allow.
*
* @return int
*/
public function maxAttempts()
{
return property_exists($this, 'maxAttempts') ? $this->maxAttempts : 5;
}
/**
* Get the number of minutes to throttle for.
*
* @return int
*/
public function decayMinutes()
{
return property_exists($this, 'decayMinutes') ? $this->decayMinutes : 1;
}
}
+2 -2
View File
@@ -72,7 +72,7 @@ class LoginTest extends TestCase
public function test_bad_credentials_show_error()
{
$this->invalid_login()
->assertHasErrors('password');
->assertHasErrors('email');
}
public function test_bad_credentials_show_error_due_to_login_throttling()
@@ -83,7 +83,7 @@ class LoginTest extends TestCase
// 5th invalid login attempt should return validation error
$this->invalid_login()
->assertHasErrors('password');
->assertHasErrors('email');
}
private function invalid_login()
+1 -6
View File
@@ -32,12 +32,7 @@ mix.js(`${SRC}/js/filament.js`, 'js')
*
* @link https://laravel.com/docs/master/mix#postcss
*/
mix.postCss(`${SRC}/css/filament.css`, 'css', [
require('postcss-import'),
require('tailwindcss'),
require('postcss-nested'),
require('autoprefixer'),
])
mix.postCss(`${SRC}/css/filament.css`, 'css')
/**
* Sourcemaps