Laravel结合Redis实现黑名单、倒计时、防刷功能

新建的网站,如何限制别人恶意攻击、频繁请求接口,导致数据库崩溃?我们可以使用Redis对请求的IP做一个简单的限制。

一、设计思路

1、Redis中使用有序set表存放黑名单列表、频繁请求列表。

2、用户访问,设置一个锁,数值为1,过期时间10秒。

3、用户每次请求接口1次,锁的数值加1。在10秒内接口访问次数超过20次,则把该用户IP或uid添加到频繁请求列表中,score的值为当前时间,数据库表频繁请求次加1。

4、若频繁请求次数超过设定次数,则添加到redis黑名单列表中。

二、前期准备

1、在app\http\common中创建RedisKey.php

<?php  namespace App\Http\Common;  class RedisKey {     public static $USER_BLACK_LIST = "user:black:list";//黑名单列表     public static $USER_FREQUENT_REQUEST_LIST = "user:frequent:request:list";//频繁请求列表     public static $USER_FREQUENT_REQUEST_LOCK = "user:frequent:request:lock";//锁 }

2、创建数据库表

Laravel结合Redis实现黑名单、倒计时、防刷功能

user表

3、使用命令创建CheckRequest.php路由中间件

php artisan make:middleware CheckRequest

三、实现代码

<?php  namespace App\Http\Middleware;  use App\Http\Common\Code; use App\Http\Common\RedisKey; use App\Models\FrontUser; use Closure; use Illuminate\Http\Request; use Illuminate\Support\Facades\Redis;  class CheckRequest {     /**      * Handle an incoming request.      *      * @param Request $request      * @param Closure $next      * @return mixed      */     public function handle($request, Closure $next)     {         $ip = request()->ip();         //查看redis黑名单中是否存在该IP         $isBlack = Redis::zscore(RedisKey::$USER_BLACK_LIST, $ip);         if ($isBlack) {             return ["code" => Code::$USER_BLACK, "msg" => "由于您近期异常请求过于频繁,已限制访问。如需取消限制,请联系管理员:邮箱1048672466@qq.com!"];         }         $user = new FrontUser();         $isUser = $user->where(["ip" => $ip])->first();         //数据库中已设置为黑名单或频繁请求数大于等于10         if ($isUser) {         //查看数据库表中频繁请求次数是否超过10次,是就把该用户列入黑名单并修改相关字段             if ($isUser->black_list === 1 || $isUser->frequent_num >= 10) {                 $isUser->black_list = 1;                 $isUser->save();                 Redis::zadd(RedisKey::$USER_BLACK_LIST, 1, $isUser->ip);                 return ["code" => Code::$USER_BLACK, "msg" => "由于您近期异常请求过于频繁,已限制访问。如需取消限制,请联系管理员:邮箱1048672466@qq.com!"];             }         }         $time = 5;//锁过期时间         $limit = 20;//5秒内请求次数,超过就触发防刷机制         $lock_time = 60;//每次防刷的锁60秒         //redis频繁请求列表         $start_time = Redis::zscore(RedisKey::$USER_FREQUENT_REQUEST_LIST, $ip);         //如果redis频繁请求列表中存在该用户IP,且间隔当前时间少于60秒         if (time() - $start_time < $lock_time) {             //返回剩余时间             return response(["code" => Code::$USER_FREQUENT, "msg" => "频繁请求!", "data" => $lock_time - (time() - $start_time)]);         }         $frequentLock = RedisKey::$USER_FREQUENT_REQUEST_LOCK . ":" . $ip;         $isFrequent = Redis::get($frequentLock);         if (!$isFrequent) {             Redis::setex($frequentLock, $time, 1); //设置锁             return $next($request);         }         Redis::incr($frequentLock);//锁过期时间类数值自增         //设定时间内请求次数大于设定次数,触发防刷机制         if ($isFrequent > $limit) {             Redis::zadd(RedisKey::$USER_FREQUENT_REQUEST_LIST, time(), $ip);             Redis::expire(RedisKey::$USER_FREQUENT_REQUEST_LIST, 60 * 5);             $isUser->increment("frequent_num");             $isUser->save();         }         return $next($request);     } }

四、实现效果

Laravel结合Redis实现黑名单、倒计时、防刷功能

效果图

您可能还会对下面的文章感兴趣: