Laravel 登录失败次数限制 等待时间递增

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

<?php

namespace 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 是成功登入後,將時間、次數重設,下一次再登入錯誤後,將從頭開始計數。

此時登录失败次数限制的功能已改寫完成,再次登入並輸入錯誤的帳號或密碼,重複數次即可看到結果。

本作品采用《CC 协议》,转载必须注明作者和本文链接
本帖由系统于 2年前 自动加精
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 6

file

尝试运行了下,就报错了~

2年前 评论

@shadow123 您是不是使用 Laravel 5.4? 此功能 Laravel 5.5 以上才支援。

2年前 评论

@Chenshin 看到了 是我版本问题 ;麻烦了

2年前 评论
return parent::hit($key, $decayMinutes);

这里应该乘以 60 吧

return parent::hit($key, $decayMinutes * 60);
1年前 评论

提示怎样即时反馈

9个月前 评论

@kinchuam 请问要提示什么即时反馈?

9个月前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!