GithubHelp home page GithubHelp logo

Comments (6)

Jubeki avatar Jubeki commented on June 30, 2024 3

The throttling should be applied to the /livewire endpoint. Otherwise the following authorization example would be meaningless: https://laravel-livewire.com/docs/2.x/authorization

You could make a feature request on https://github.com/livewire/livewire for middleware for components.
There is also the livewire discord for questions and ideas: https://discord.gg/livewire

I will tag Caleb here. Maybe he has some ideas.
cc @calebporzio

from tall.

Jubeki avatar Jubeki commented on June 30, 2024 1

You can update your livewire config:

  1. Publish the config using php artisan livewire:publish
  2. Edit config/livewire.php
return [
  // ...

  'middleware_group' => ['web', 'throttle:5,1'],

  // ...
];

This will then be applied to all Livewire Components

Edit: Otherwise you can take a look at traits where you implement your throttle logic:
https://laravel-livewire.com/docs/2.x/traits

from tall.

imliam avatar imliam commented on June 30, 2024

Choosing a custom username is as simple as editing the email fields there, just as you'd override the username() method in the default LoginController - I don't think that concern is missing functionality necessarily.

However, I will admit that we forgot to implement the login throttling behaviour that comes from the ThrottleLogins trait - we'll have to see about adding that back and see what the nicest way will be.

from tall.

glaesser avatar glaesser commented on June 30, 2024

Choosing a custom username is as simple as editing the email fields there, just as you'd override the username() method in the default LoginController - I don't think that concern is missing functionality necessarily.

However, I will admit that we forgot to implement the login throttling behaviour that comes from the ThrottleLogins trait - we'll have to see about adding that back and see what the nicest way will be.

Did this ever materialize? Searching for any sort of login-throttling behaviour in vain. It's not like we can just use throttling middleware from the routes file as livewire POSTs to it's own endpoints and not the component/page route. And the "ThrottleLogins" trait requires use of $request, which we don't have access to in livewire components. Any suggestions?

from tall.

glaesser avatar glaesser commented on June 30, 2024

@Jubeki thanks for the pointers! Will the throttling apply to the livewire endpoint (/livewire/*) or just the frontend route (on which you could already use regular laravel route throttling)?

Ideally you would only want very conservative/slow throttling applied to the login/register methods.

from tall.

mikesaintsg avatar mikesaintsg commented on June 30, 2024

@Jubeki great solution as a fail-safe on all routes but blows up a route with an ugly 403 error. Instead, I found a way to use a validation rule for more specific throttling and a graceful way to relay that to the end user.

@glaesser thanks to @stevebauman I was able to come up with a custom throttle validation rule that follows the laravel ui methodology and by extension a custom Lockout Event since both required access to the Request object.

Give this a shot when you get the chance:

App\Events\Lockout.php

<?php

namespace App\Events;

class Lockout
{
    public $key, $identifier;

    public function __construct(string $key, string $identifier = '')
    {
        $this->key = $key;
        $this->identifier = $identifier;
    }
}

App\Rules\Throttle.php

<?php

namespace App\Rules;

use Illuminate\Cache\RateLimiter;
use Illuminate\Contracts\Validation\Rule;

class Throttle implements Rule
{
    protected $throttleKey, $maxAttempts, $decayInMinutes, $event;

    public function __construct($throttleKey, $maxAttempts, $decayInMinutes, $event = null)
    {
        $this->throttleKey = $throttleKey;
        $this->maxAttempts = $maxAttempts;
        $this->decayInMinutes = $decayInMinutes;
        $this->event = $event;
    }

    public function passes($attribute, $value): bool
    {
        if ($this->hasTooManyAttempts()) {

            if($this->event) {

                event(new $this->event($this->throttleKey, $value));
            }

            return false;
        }

        $this->incrementAttempts();

        return true;
    }

    public function message()
    {
        $seconds = $this->limiter()
            ->availableIn($this->throttleKey);

        return trans('auth.throttle', [
            'seconds' => $seconds,
            'minutes' => ceil($seconds / 60),
        ]);
    }

    protected function hasTooManyAttempts()
    {
        return $this->limiter()->tooManyAttempts(
            $this->throttleKey, $this->maxAttempts
        );
    }

    protected function limiter()
    {
        return app(RateLimiter::class);
    }

    protected function incrementAttempts()
    {
        $this->limiter()->hit(
            $this->throttleKey, $this->decayInMinutes * 60
        );
    }
}

App\Http\Livewire\Auth\Login.php

<?php

namespace App\Http\Livewire\Auth;

use App\Events\Lockout;
use App\Rules\Throttle;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Str;
use Livewire\Component;

class Login extends Component
{
    public $ip, $email, $password, $remember = false;

    protected function rules(): array
    {
        return [
            'email' => [
                'required',
                'email',
                new Throttle($this->throttleKey(), 5, 1, Lockout::class)],
            'password' => ['required'],
        ];
    }

    public function mount(Request $request)
    {
        $this->ip = $request->ip();
    }

    public function login()
    {
        $input = $this->validate();

        if (Auth::attempt($input, $this->remember)) {
            session()->regenerate();

            return redirect()->intended(route('home'));
        }

        return $this->addError('password', trans('auth.failed'));
    }

    protected function throttleKey()
    {
        return Str::lower("$this->email|$this->ip");
    }

    public function render()
    {
        return view('livewire.auth.login');
    }
}

from tall.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.