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

2021年2月14日 225点热度 0人点赞 0条评论


图片

每天进步一点点...

新建的网站,如何限制别人恶意攻击、频繁请求接口,导致数据库崩溃?我们可以使用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、创建数据库表

图片

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" => "由于您近期异常请求过于频繁,已限制访问。如需取消限制,请联系管理员:邮箱[email protected]!"];
}
$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" => "由于您近期异常请求过于频繁,已限制访问。如需取消限制,请联系管理员:邮箱[email protected]!"];
}
}
$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);
}
}

四、实现效果

图片

效果图

来源:

https://www.toutiao.com/i6927853311446303245/

“IT大咖说”欢迎广大技术人员投稿,投稿邮箱:[email protected]


图片

来都来了,走啥走,留个言呗~

 IT大咖说  |  关于版权 

由“IT大咖说(ID:itdakashuo)”原创的文章,转载时请注明作者、出处及微信公众号。投稿、约稿、转载请加微信:ITDKS10(备注:投稿),茉莉小姐姐会及时与您联系!

感谢您对IT大咖说的热心支持!

相关推荐

推荐文章

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

root

这个人很懒,什么都没留下

文章评论