Laravel 本身已实现了登入失败次数限制的功能。在使用 Laravel 的登入验证时,登入失败次数限制预设是:
失败5次,1分钟后
才可再次登入但如果要求的功能是:
失败3次,1分钟后
才可登入再失败3次,3分钟后
才可登入再失败3次,5分钟后
才可登入...要如何实现?下面将示範此登入失败次数限制的功能。
版本
Laravel 5.8 以上
改写登入类别设定
app\Http\Controllers\Auth\LoginController.php
<?php...use Illuminate\Foundation\Auth\AuthenticatesUsers;use Illuminate\Http\Request;use App\Cache\AdvancedRateLimiter;class LoginController extends Controller{ use AuthenticatesUsers; ... /** * The maximum number of attempts to allow. * * @var int */ protected $maxAttempts = 3; /** * The number of minutes to throttle for. * * @var int|float|int[]|float[] */ protected $decayMinutes = [1, 3, 5]; /** * Get the rate limiter instance. * * @return \App\Cache\AdvancedRateLimiter */ protected function limiter() { return app(AdvancedRateLimiter::class); } /** * 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), array_map(function ($decayMinute) { return (int) ($decayMinute * 60); }, (array) $this->decayMinutes()) ); }}
在 LoginController
类中,增加自订方法覆盖 AuthenticatesUsers
类原本的方法:
limiter
方法是返回登入失败次数限制的类,原本是返回RateLimiter
类(实现登入失败次数限制的类),但本例要扩充新方法,因此返回了我们下面创建的子类别AdvancedRateLimiter
。$maxAttempts
属性是设定登入失败次数。$decayMinutes
属性是登入失败达上限后,须等待的分钟数。但我们要实现的功能是每次都等待不一样的时间,因此传入一个阵列,输入每次的等待分钟数。如果只是要修改 Laravel 原本的错误次数设定,新增 $maxAttempts
属性及 $decayMinutes
属性并设定值即可完成。
扩充登入失败次数限制功能
新增类别 AdvancedRateLimiter
:
app\Cache\AdvancedRateLimiter.php
<?phpnamespace App\Cache;use Illuminate\Cache\RateLimiter;class AdvancedRateLimiter extends RateLimiter{ /** * Increment the counter for a given key for a given decay time. * * @param string $key * @param int|int[] $decaySeconds * @return int */ public function hit($key, $decaySeconds = 60) { if (is_array($decaySeconds)) { if (! $this->cache->has($key.':timer')) { if (! $this->cache->has($key.':step')) { $this->cache->add($key.':step', 0, 86400); } else { $this->cache->increment($key.':step'); } } $step = $this->cache->get($key.':step', 0); $step = $step < count($decaySeconds) ? $step : count($decaySeconds) - 1; $decaySeconds = $decaySeconds[$step]; } return parent::hit($key, $decaySeconds); } /** * Clear the hits and lockout timer for the given key. * * @param string $key * @return void */ public function clear($key) { $this->cache->forget($key.':step'); parent::clear($key); }}
hit
方法是在登入错误后,执行登入错误次数记录递增的方法。为了实现每次登入错误等待的时间可以不一样,我们让传入的变数 $decayMinutes
可以接受传入阵列,第一次登入错误等待时间为 阵列[0]
的分钟数(本例为1分钟),第二次为 阵列[1]
的分钟数(例:3分钟),而第三次为 阵列[2]
的分钟数(例:5分钟),之后的登入错误等待时间皆为阵列的最后的元素的分钟数。clear
方法是成功登入后,将时间、次数重设,下一次再登入错误后,将从头开始计数。此时登入失败次数限制的功能已改写完成,再次登入并输入错误的帐号或密码,重複数次即可看到结果。