美文网首页PHP经验分享
laravel登录失败过多限制登录

laravel登录失败过多限制登录

作者: 杏花_我不想活了 | 来源:发表于2021-04-16 14:25 被阅读0次

    简单使用

    laravel有自带的登录限制:ThrottlesLogins;位于Illuminate\Foundation\Auth\ThrottlesLogins,是一个trait,use进来即可;这个trait实现了1分钟内登录5次失败就禁止登录1分钟.
    登录代码:

      public function postLogin(Request $request)
      {
            if ($this->hasTooManyLoginAttempts($request)) {
                $this->fireLockoutEvent($request);
    
                return $this->sendLockoutResponse($request);
            }
    
            $credentials = $request->only([$this->username(), 'password']);
    
            /** @var \Illuminate\Validation\Validator $validator */
            $validator = Validator::make($credentials, [
                $this->username() => 'required',
                'password' => 'required',
            ]);
    
            if ($validator->fails()) {
                $this->incrementLoginAttempts($request);
    
                return back()->withInput()->withErrors($validator);
            }
    
            if (! $this->guard()->attempt($credentials)) {
                $this->incrementLoginAttempts($request);
    
                return back()->withInput()->withErrors([
                    'password' => $this->getFailedLoginMessage(),
                ]);
            }
    
            return $this->sendLoginResponse($request);
        }
    

    它的实现很简单,代码并不复杂,两个缓存:
    一个缓存记录它失败的次数;键为用户名和ip的组合:Str::lower($request->input($this->username())).'|'.$request->ip();;值为登录失败次数;缓存有效期即为登录失败次数的限定时长,默认一分钟。
    另一个缓存则记录它失败设定次数后后锁定时长; 键为上面的键拼接上:timer;值为第一次登录失败时的时间加上限制登录时长;缓存有效期即为限制登录时长,默认一分钟

    在登录时根据第一个缓存判断失败次数是否达到设定次数;若没有,走正常的登录流程,若是,则锁定禁止登录。登录失败时通过方法$this->incrementLoginAttempts($request);这个方法调用如下:

        public function hit($key, $decayMinutes = 1)
        {
            $this->cache->add(
                $key.':timer', $this->availableAt($decayMinutes * 60), $decayMinutes
            );
    
            $added = $this->cache->add($key, 0, $decayMinutes);
    
            $hits = (int) $this->cache->increment($key);
    
            if (! $added && $hits == 1) {
                $this->cache->put($key, 1, $decayMinutes);
            }
    
            return $hits;
        }
    

    如果是第一次登录失败就初始化两个缓存,否则就增加一次错误次数increment($key)
    这个trait主要的还是防刷机器登录的,因为他在第一次登录失败就写入了第二个缓存(add 方法将只存储缓存中不存在的数据,不会覆写),这就导致了一个问题:假如我在这一分钟的第一秒失败了第一次,而在这一分钟的最后一秒失败了最后一次的话,那我下一分钟还是可以继续登录。个人认为应该是达到错误次数后才写入第二个缓存。

    如果有其他限制需求怎么做呢

    也很简单,复制一份ThrottlesLogins和RateLimiter出来修改即可。

    1. 修改最大错误登录次数,修改ThrottlesLogins的maxAttempts()方法
        public function maxAttempts()
        {
            return property_exists($this, 'maxAttempts') ? $this->maxAttempts : 5;
        }
    
    1. 修改限制登录时长,修改ThrottlesLogins的decayMinutes()方法; 单位:分钟
        public function decayMinutes()
        {
            return property_exists($this, 'decayMinutes') ? $this->decayMinutes : 1;
        }
    

    需要注意的是,修改了限制登录时长的同时也修改了错误登录时间区间;因为上面提到的hit()方法在写入第一个缓存时使用的缓存有效期也是方法decayMinutes()的返回值。所以我们有需要就修改RateLimiter的hit()方法;

    例子:20分钟内失败5次锁定30分钟,从最后一次登录失败开始算

        public function hit($key, $decayMinutes = 1)
        {
            $added = $this->cache->add($key, 0, 20);
    
            $hits = (int) $this->cache->increment($key);
    
            if (! $added && $hits == 1) {
                $this->cache->put($key, 1, 20);
            }
    
            if($hits == 5){
                $this->cache->add(
                    $key.':timer', $this->availableAt($decayMinutes * 60), $decayMinutes
                );
            }
    
            return $hits;
        }
    

    其中的细节也可以慢慢修改,尽善尽美。比如限制登录的提示信息等;若还有其他更复杂的限制需求,修改这几个方法就可达到要求,源代码也就这两个类(一个trait一个class)。

    相关文章

      网友评论

        本文标题:laravel登录失败过多限制登录

        本文链接:https://www.haomeiwen.com/subject/zuoslltx.html