很多站长朋友们都不太清楚phpredis防刷,今天小编就来给大家整理phpredis防刷,希望对各位有所帮助,具体内容如下:
本文目录一览: 1、 php在程序结束后释放redis缓存 2、 订单超时,活动过期解决方案:php监听redis键重复触发引发事件 3、 后台登陆防刷、防爆破以及正常的登录校验 4、 php redis如何使用 php在程序结束后释放redis缓存php在程序结束后释放redis缓存 :PHP的unset()函数用来清除、销毁变量,不用的变量,我们可以用unset()将它销毁。但是某些时候,用unset()却无法达到销毁变量占用的内存!
订单超时,活动过期解决方案:php监听redis键重复触发引发事件订单超时,活动过期解决方案:php监听redis键重复触发引发事件
Redis的2.8.0版本之后可用,键空间消息(Redis Keyspace Notifications),配合2.0.0版本之后的SUBSCRIBE 可以完成这个定时任务的操作了,定时的单位是秒。
1.我们先订阅频道称为 redisChat
2.现在,我们重新开启个redis客户端,然后在同一个频道redisChat发布消息,订阅者可以接收到消息。
接收到的消息如下:
3.Key过期事件的Redis配置
需要这里配置notify-keyspace-events的参数为“EX” .X代表了过期事件。notify-keyspace-events “Ex”保存配置后,重启Redis的服务,使配置生效。
PHP Redis实现订阅键空间通知
redis实例化类:
redis.class.php
1个
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18岁
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
//遇到类别重复的报错,所有叫Redis2
classRedis2
{
private$redis;
publicfunction__construct($host= '127.0.0.1', $port= 6379)
{
$this->redis = newRedis();
$this->redis->connect($host, $port);
}
publicfunctionsetex($key, $time, $val)
{
return$this->redis->setex($key, $time, $val);
}
publicfunctionset($key, $val)
{
return$this->redis->set($key, $val);
}
publicfunctionget($key)
{
return$this->redis->get($key);
}
publicfunctionexpire($key= null, $time= 0)
{
return$this->redis->expire($key, $time);
}
publicfunctionpsubscribe($patterns= array(), $callback)
{
$this->redis->psubscribe($patterns, $callback);
}
publicfunctionsetOption()
{
$this->redis->setOption(\Redis::OPT_READ_TIMEOUT, -1);
}
}
过期事件的订阅:
psubscribe.php
1个
2
3
4
5
6
7
8
9
10
11
12
13
14
15
require_once'./Redis.class.php';
$redis= new\Redis2();
// 解决Redis客户端订阅时候超时情况
$redis->setOption();
$redis->psubscribe(array('__keyevent@0__:expired'), 'keyCallback');
// 回调函数,这里写处理逻辑
functionkeyCallback($redis, $pattern, $chan, $msg)
{
echo"Pattern: $pattern\n";
echo"Channel: $chan\n";
echo"Payl
oad: $msg\n\n";
//keyCallback为订阅事件后的回调函数,这里写业务处理逻辑,
//比如前面提到的商品不支付自动撤单,这里就可以根据订单id,来实现自动撤单
}
设置过期事件:
index.php
1个
2
3
4
require_once'./Redis.class.php';
$redis= new\Redis2();
$order_id= 123;
$redis->setex('order_id',10,$order_id);
先用命令行模式执行 psubscribe.php
在浏览器访问 index.php
效果如下:
后台登陆防刷、防爆破以及正常的登录校验前几天项目上需要对一个正常登陆接口,以及忘记密码的接口进行防爆破处理,这里我用nginx,redis,以及前端的一些简单的图形拖动来做一个简单的安全机制,可能有不完善的地方,大家可以提出来意见。
其实一个接口是无法完全避免接口爆破的,区分人和机器或许可以使用谷歌的图片验证机制,但是我们一般简单项目没必要做那么复杂的,只需要确保不正常的访问频率不会爆破出我们的用户信息,以及让我们机器的处理流量保存在可控范围即可。
验证码只能60s获取一次 并且3小时内只能获取三次,超过次数提升获取频繁,稍后再试。
正常登录1小时内失败6次账号自动锁定,1小时之后自动解锁。
获取验证码无论输入的账号存在不存在均显示发送成功,但是实际不存在的账号不会正常发送。
4.登录失败,账号不存在密码错误不再提示账号不存在等等,而是统一显示账号或密码错误。5.忘记密码前端部分增加滑动校验,60倒计时无法点击发送验证码。前后端共同校验。6.技术限制系统此接口的访问频率。
前端部分可以在这个地址看看这几个简单的组件,这次我们就使用最简单的,滑动拖动即可。
<drag-verify
ref="dragVerify"
:width="width"
:height="height"
text="请按住滑块拖动"
successText="验证通过"
:isPassing.sync="isPassing"
background="#ccc"
completedBg="rgb(105, 231, 251)"
handlerIcon="el-icon-d-arrow-right"
successIcon="el-icon-circle-check"
@passcallback="passcallback"
>
</drag-verify>
用户滑动之后需要加上60s倒计时,这块我们使用定时器实现即可,以及邮箱和手机号的正确性校验,不正确则弹窗提示。
this.countDown = 60;
timer = setInterval(() => {
if (this.countDown - 1 >= 0) {
this.countDown -= 1;
} else {
clearInterval(timer);
timer = null;
}
}, 1000);
<el-button disabled type="text" v-show="time > 0">
{{ time > 0 ? `${time}` : "" }} s之后重试</el-button>
验证邮箱手机号可以使用正则校验进行。
mobileReg = /^1\d{10}$/;
emailReg = /^([A-Za-z0-9_\-\.\u4e00-\u9fa5])+\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,8})$/;
前端大体思路就是,进行滑块验证,拖到右边之后,60s之内无法操作,60s到期之后自动复原,
显示倒计时时间。这个只能防止用户在页面上多次点击,造成一个验证的假象,如果直接对后端接口爆破,则无法避免。
这是大概的流程图,图中还有些细节问题下面慢慢讲解。
这块本来我想用java或者kotlin写,但是历史项目用go写的,重写的话还有其他一些改动,所以继续使用golang完成这部分逻辑。
先定义一个结构体,然后我们来分析下需要哪些字段来实现我们的业务。
type CommonLogin struct {
CreateTime time.Time
LastTime time.Time
Times uint8
}
// 登录的前置校验
func beforeCommonLoginValid(key string, r *redis.Client, field string) (bool, error) {
// redis中是否存在账号
result, err := r.HExists(field, key).Result()
if err != nil {
fmt.Printf("从redis中获取用户账户失败,账户为: %s", key)
return false, err
}
if result {
login := CommonLogin{}
// 存在账号 说明之前登录失败过 且自从上次失败未登录成功过
commonLogin, err := r.HGet(field, key).Result()
if err != nil {
return false, err
}
json.Unmarshal([]byte(commonLogin), login)
if login.Times < 6 {
return true, nil
}
// 是否在1小时内失败了6次
if login.Times >= 6 {
// 否
if time.Now().Sub(login.CreateTime) > time.Hour*1 {
// 连续输错6次时长大于1小时 解锁
r.HDel(field, key)
return true, nil
} else {
fmt.Printf("用户%s于1小时之内连续登录失败6次,账号锁定,1小时后重试。", key)
return false, nil
}
}
}
// redis中不存在重试记录
return true, nil
}
在所有的登录判断的出口,调用此方法即可,例如用户名密码错误,acl校验未通过等等。
其实原理差不多,唯一的区别就是多了一个获取验证码时间间隔校验。
func beforeForgotPasswordValid(key string, r *redis.Client, field string) (bool, error) {
// redis中是否存在账号
result, err := r.HExists(field, key).Result()
if err != nil {
fmt.Printf("从redis中获取用户账户失败,账户为: %s", key)
return false, err
}
login := CommonLogin{}
// 账号存在
if result {
commonLogin, err := r.HGet(field, key).Result()
if err != nil {
return false, err
}
json.Unmarshal([]byte(commonLogin), login)
// 获取验证码间隔时长不能小于60s
if time.Now().Sub(login.LastTime) < time.Second*60 {
fmt.Printf("用户获取验证码间隔小于60s")
return false, nil
}
if login.Times < 3 {
return true, nil
}
// 是否在1小时内获取了3次
if login.Times >= 3 {
// 否
if time.Now().Sub(login.CreateTime) > time.Hour*3 {
// 连续输错6次时长大于1小时 解锁
r.HDel(field, key)
return true, nil
} else {
fmt.Printf("用户%s于3小时之内连续获取验证码3次,账号锁定,3小时后重试。", key)
return false, nil
}
}
}
return true, nil
}
// 更新获取验证码的时间
func afterForgotPasswordValid(key string, r *redis.Client, field string) {
login := CommonLogin{}
commonLogin, _ := r.HGet(field, key).Result()
json.Unmarshal([]byte(commonLogin), login)
// 验证码发送成功
result, _ := r.HExists(field, key).Result()
if result {
login.Times = login.Times + 1
login.LastTime = time.Now()
data, _ := json.Marshal(login)
r.HSet(field, key, data)
} else {
login.Times = 1
login.LastTime = time.Now()
login.CreateTime = login.LastTime
data, _ := json.Marshal(login)
r.HSet(field, key, data)
}
}
nginx是一个非常强大的中间价,在安全方面,我们可以用它来限制来自于同一机器的访问频率,可以做黑名单功能等等,当然有人会说ip代{过}{滤}理池之类的,我们此次演示的只是简单demo,恶意攻击当然需要专业防护了。
具体google一下,看这两篇官方文档。
具体的配置其实很简单了。
限制远程同ip访问频率。
limit_req_zone$binary_remote_addrzone=perip:10mrate=1r/s;
$binary_remote_addr 表示通过remote
addr这个标识来做限制,“binary ”的目的是缩写内存占用量,是限制同一客户端ip地址
zone=one:10m表示生成一个大小为10M,名字为one的内存区域,用来存储访问的频次信息
rate=1r/s表示允许相同标识的客户端的访问频次,这里限制的是每秒1次,还可以有比如30r/m的
location ^~ /api/xxx {
limit_req zone=perip nodelay;
limit_req_status 503;
proxy_pass http://正确地址;
}
上面配置意思就是超过频率返回503,服务不可用。
使用jmeter进行压力测试:1s 10个请求,我们预期只有1个请求成功,其他的返回503.
php redis如何使用开始在
PHP
中使用
Redis
前,要确保已经安装了
redis
服务及
PHP
redis
驱动,且你的机器上能正常使用
PHP。
PHP安装redis扩展
/usr/local/php/bin/phpize
#php安装后的路径
./configure
--with-php-config=/usr/local/php/bin/php-config
make
make
install
修改php.ini文件
vi
/usr/local/php/lib/php.ini
增加如下内容:
extension_dir
=
"/usr/local/php/lib/php/extensions/no-debug-zts-20090626"
extension=redis.so
安装完成后重启php-fpm
或
apache。查看phpinfo信息,就能看到redis扩展。
连接到
redis
服务
<?php
//连接本地的
Redis
服务
$redis
=
new
Redis();
$redis->connect('127.0.0.1',
6379);
echo
"Connection
to
server
sucessfully";
//查看服务是否运行
echo
"Server
is
running:
"
.
$redis->ping();
?>
执行脚本,输出结果为:
Connection
to
server
sucessfully
Server
is
running:
PONG
Redis
PHP
String(字符串)
实例
<?php
//连接本地的
Redis
服务
$redis
=
new
Redis();
$redis->connect('127.0.0.1',
6379);
echo
"Connection
to
server
sucessfully";
//设置
redis
字符串数据
$redis->set("tutorial-name",
"Redis
tutorial");
//
获取存储的数据并输出
echo
"Stored
string
in
redis::
"
.
jedis.get("tutorial-name");
?>
执行脚本,输出结果为:
Connection
to
server
sucessfully
Stored
string
in
redis::
Redis
tutorial
Redis
PHP
List(列表)
实例
<?php
//连接本地的
Redis
服务
$redis
=
new
Redis();
$redis->connect('127.0.0.1',
6379);
echo
"Connection
to
server
sucessfully";
//存储数据到列表中
$redis->lpush("tutorial-list",
"Redis");
$redis->lpush("tutorial-list",
"Mongodb");
$redis->lpush("tutorial-list",
"Mysql");
//
获取存储的数据并输出
$arList
=
$redis->lrange("tutorial-list",
,5);
echo
"Stored
string
in
redis::
"
print_r($arList);
?>
执行脚本,输出结果为:
Connection
to
server
sucessfully
Stored
string
in
redis::
Redis
Mongodb
Mysql
Redis
PHP
Keys
实例
<?php
//连接本地的
Redis
服务
$redis
=
new
Redis();
$redis->connect('127.0.0.1',
6379);
echo
"Connection
to
server
sucessfully";
//
获取数据并输出
$arList
=
$redis->keys("*");
echo
"Stored
keys
in
redis::
"
print_r($arList);
?>
执行脚本,输出结果为:
Connection
to
server
sucessfully
Stored
string
in
redis::
tutorial-name
tutorial-list
关于phpredis防刷的介绍到此就结束了,不知道本篇文章是否对您有帮助呢?如果你还想了解更多此类信息,记得收藏关注本站,我们会不定期更新哦。
查看更多关于phpredis防刷 php防cc的详细内容...