Laravel:在自定义登录中集成Throttle

16

如果我没有使用Laravel默认提供的LoginController,我该如何集成Laravel节流?

这是我的控制器:

  use AuthenticatesUsers;

  //function for login
  public function login(Request $requests){
    $username = $requests->username;
    $password = $requests->password;

    /**to login using email or username**/
    if(filter_var($username, FILTER_VALIDATE_EMAIL)) {

      Auth::attempt(['email' => $username, 'password' => $password]);
    } else {

      Auth::attempt(['username' => $username, 'password' => $password]);
    }


    if(Auth::check()){
      if(Auth::user()->type_user == 0){

        return view('users.dashboard');

      }
      else{
        return view('admin.dashboard');
      }
    }
    else{

      return Redirect::back()->withInput()->withErrors(['message'=>$login_error],'login');

    }
  }

我想限制登录失败次数,但是我似乎无法使用自己的控制器使其工作。你们能帮我吗?


在您的登录控制器中使用“use ThrottlesLogins;”作为节流特性。 - Muhammad Sadiq
仍然无法工作。:( - JaneTho
7个回答

11
在你的方法内添加以下代码。将它作为第一件事。
// If the class is using the ThrottlesLogins trait, we can automatically throttle
// the login attempts for this application. We'll key this by the username and
// the IP address of the client making these requests into this application.
if ($this->hasTooManyLoginAttempts($request)) {
    $this->fireLockoutEvent($request);
    return $this->sendLockoutResponse($request);
}

现在,在登录失败的地方添加以下代码。这将增加尝试失败的计数。

$this->incrementLoginAttempts($request);

登录成功后,请添加以下代码以进行重置。

$this->clearLoginAttempts($request);

如何通过电子邮件而非用户名进行密钥验证? - Hkm Sadek
1
同时,您也可以重写 Illuminate\Foundation\Auth\ThrottlesLogins::throttleKey() 方法,并使用您所需的键。 - Bence Szalai

6

试着将限流功能添加到你的控制器构造函数中,就像下面这样:

/**
 * Create a new login controller instance.
 *
 * @return void
 */
public function __construct()
{
    $this->middleware('throttle:3,1')->only('login');
}

很遗憾,Laravel文档并没有详细说明节流(throttling)的内容:https://laravel.com/docs/6.x/authentication#login-throttling。不过,字符串中的 "3,1" 部分对应于最多尝试 3 次登录,每次尝试间隔 1 分钟。
可以在 /project-root/laravel/app/Http/Kernel.php 文件中的 routeMiddleware 数组中定义 throttle,例如:'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,。这种方法在 Laravel 文档中有解释:https://laravel.com/docs/6.x/middleware#assigning-middleware-to-routes

4

使用位于 Illuminate\Foundation\Auth 中的 Trait ThrottlesLogins 并覆盖下面提到的 2 个函数。我已在 Laravel 5.6 上进行了测试,运行良好。

public function maxAttempts()
{
    //Lock out on 5th Login Attempt
    return 5;
}

public function decayMinutes()
{
    //Lock for 1 minute
    return 1;
}

3
除了覆盖函数外,你还可以使用属性:protected $maxAttempts = 3; protected $decayMinutes = 1;(如果需要的话可以是protected或public)。 - Arno van Oordt

2

虽然这个答案很晚,但是这就是我所做的,而且它起作用了。我希望它也能帮助到你。我正在使用laravel 5.2。

<?php

namespace App\Http\Controllers;

use App\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\MessageBag;
use Cookie;
use Illuminate\Foundation\Auth\ThrottlesLogins;
use Illuminate\Foundation\Auth\AuthenticatesAndRegistersUsers;

class UserController extends Controller
{
/** Add This line on top */
use AuthenticatesAndRegistersUsers,ThrottlesLogins;
/** This way, you can control the throttling */
protected $maxLoginAttempts=3;
protected $lockoutTime=300;

public function postUserSignIn(Request $request)
{
    /** This line should be in the start of method */
    if ($this->hasTooManyLoginAttempts($request)) {
        $this->fireLockoutEvent($request);
        return $this->sendLockoutResponse($request);
    }
    /** Validate the input */
    $validation = $this->validate($request,[
        'email' => 'required|email',
        'password' => 'required|min:4'
    ]);

    /** Validation is done, now login user */
    //else to user profile
    $check = Auth::attempt(['email' => $request['email'],'password' => $request['password']]);

    if($check){

        $user = Auth::user();
        /** Since Authentication is done, Use it here */
        $this->clearLoginAttempts($request);
        if ($user->role == 1 || $user->role == 2){
            if(Session::has('cart')){
                return redirect()->route('cart');
            }
            return redirect()->intended();
        }elseif($user->role == 99) {
            return redirect()->route('dashboard');
        }

    }else{
        /** Authentication Failed */
        $this->incrementLoginAttempts($request);
        $errors = new MessageBag(['password' => ['Email and/or Password is invalid']]);
        return redirect()->back()->withErrors($errors);
    }

}

}


1
Route::post('login', ['before' => 'throttle:2,60', 'uses' => 'YourLoginController@Login']);

油门应该在验证之后。此外,没有办法将验证响应消息发送给用户。 - Abdalla Arbab

0
if ($this->hasTooManyLoginAttempts($request)) {
            $this->fireLockoutEvent($request);

            return redirect()->route('login')->with('alert-warning', 'Too many login attempts');
        }

protected function hasTooManyLoginAttempts(Request $request)
{
   $maxLoginAttempts = 3;

   $lockoutTime = 1; // In minutes

   return $this->limiter()->tooManyAttempts(
       $this->throttleKey($request), $maxLoginAttempts, $lockoutTime
   );
}

抱歉,我应该把这个放在哪里? - JaneTho
在你的控制器中 - Bikram Maharjan
我收到了一个错误,内容为:(1/1) BadMethodCallException 方法[username]不存在。 位于Controller.php (第82行)。 - JaneTho
$this->username()AuthenticatesUsers Trait 中的一个方法。您可以在 vendor/laravel/ui/auth-backend/AuthenticatesUsers.php 文件中查看它。如果您没有覆盖它,它将返回 email。如果您在身份验证控制器中没有使用 use AuthenticatesUsers;,则会出现该错误。 - agm1984

0

尝试我的版本:

use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;

class LoginController extends Controller{
use AuthenticatesUsers;
public function login(Request $request){
    if($this->hasTooManyLoginAttempts($request)){
        $this->fireLockoutEvent($request);
        return $this->sendLockoutResponse($request);
    }else{
        if (Auth::attempt(['username' => $request->login_username, 'password' => $request->login_password])) {
        session()->put(['username'=>Auth::user()->username,'userid'=>Auth::user()->id]);
        return redirect()->intended('anydashboard');
        }else{
            $this->incrementLoginAttempts($request);
            //my '/' path is the login page, with customized response msg...
            return redirect('/')->with(['illegal'=>'Login failed, please try again!'])->withInput($request->except('password'));
        }
    }
}
}

为了使用Eloquent模型认证(默认情况下),您的AUTH_MODEL应该实现AuthenticatableContract接口,请仔细检查您的模型:

namespace App;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Auth\Authenticatable;
use Illuminate\Auth\Passwords\CanResetPassword;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
class User extends Model implements AuthenticatableContract,CanResetPasswordContract
{
use Authenticatable, CanResetPassword;
//protected $fillable = [];
...
}

不认为它起作用。我还尝试调试 $this->incrementLoginAttempts($request); 看看是否在递增,但结果只是 null - JaneTho
只需查看您的模型,就像上面一样。 - Shuo Wang

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接