nodejs实现黑名单中间件设计


Posted in NodeJs onJune 17, 2014

黑名单Schema:

/**
 * Created by YCXJ-wanglihui on 2014/5/28.
 */
'use strict';
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
//1.短暂屏蔽 2.永久屏蔽
var degree = {TEMP:1, FOREVER:2};
/**
 * 黑名单
 * @type {Schema}
 *
 * @param ip {String} 黑名单Ip
 * @param createAt {Date} 创建时间
 * @param expireTime {Date} 如果是短暂屏蔽,屏蔽到期时间
 * @param forbiddenDegree {Number} 屏蔽级别 1.短暂屏蔽 2.永久屏蔽
 * @param reason {String} 屏蔽原因
 */
var BlackList = new Schema({
    ip:{
        type: String,
        index:true
    },
    createAt:{
        type: Date,
        default: Date.now
    },
    expireTime:{
        type: Date
    },
    forbiddenDegree:{
        type: Number,
        default:degree.TEMP
    },
    reason:{
        type: String,
        default: '请求次数频繁'
    }
});
mongoose.model('BlackList', BlackList);

IP与提交记录Schema:

/**
 * Created by YCXJ-wanglihui on 2014/5/28.
 */
'use strict';
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var ObjectId = Schema.ObjectId;
/**
 * 记录参与调查问卷的回复与Ip
 * @type {Schema}
 *
 * @param answerId {ObjectId} 回复Id
 * @param createAt {Date} 创建时间
 * @param ip {String} 参与回复的人Ip
 */
var IpAnswerLog = new Schema({
    answerId: {
        type: ObjectId
    },
    createAt: {
        type: Date,
        default:Date.now
    },
    ip:{
        type: String,
        index:true
    }
});
mongoose.model('IpAnswerLog', IpAnswerLog);

相关Proxy代码:

/**
 * Created by YCXJ-wanglihui on 2014/5/28.
 */
'use strict';
var IpAnswerLog = require('../models').IpAnswerLog;
/**
 * 新建并保存
 * @param ipAnswerLog {Schema or dict}
 * @param callback
 */
var newAndSave = function(ipAnswerLog, callback){
    if(ipAnswerLog instanceof IpAnswerLog){
        ipAnswerLog.save(callback);
    }else{
        var m = new IpAnswerLog(ipAnswerLog);
        m.save(callback);
    }
}
/**
 * 一分钟内回复数
 * @param ip
 * @param callback
 */
var countOneMinuteAnswer = function(ip, callback){
    var endTime = Date.now();
    var beginTime = endTime - 1000*60*1;
    countIpAnswerByTime(beginTime, endTime, ip, callback);
}
/**
 * 一小时内回复数字
 * @param ip
 * @param callback
 */
var countOneHourAnswer = function(ip, callback){
    var endTime = Date.now();
    var beginTime = endTime - 1000*60*60*1;
    countIpAnswerByTime(beginTime, endTime, ip, callback);
}
/**
 * 一天内回复
 * @param ip
 * @param callback
 */
var countOneDayAnswer = function(ip, callback){
    var endTime = Date.now();
    var beginTime = endTime - 1000*60*60*24;
    countIpAnswerByTime(beginTime, endTime, ip, callback);
}
/**
 * 计算某段时间内回复数
 * @param beginTime {Number} 开始时间 时间戳
 * @param endTime   {Number} 结束时间 如果为null,使用当前时间 时间戳
 * @param ip    {String} Ip地址
 * @param callback
 */
var countIpAnswerByTime = function(beginTime, endTime, ip, callback){
    if(!endTime){
        endTime = Date.now();
    }
    IpAnswerLog.count({ip:ip, '$and':{$lt:beginTime, $gt:endTime}}, callback);
}
exports.countIpAnswerByTime =countIpAnswerByTime;
exports.countOneDayAnswer = countOneDayAnswer;
exports.countOneHourAnswer = countOneHourAnswer;
exports.countOneMinuteAnswer = countOneMinuteAnswer;
exports.newAndSave = newAndSave;

黑名单Proxy:

/**
 * Created by YCXJ-wanglihui on 2014/5/28.
 */
'use strict';
var BlackList = require('../models').BlackList;
/**
 * 新建并保存
 * @param backList {BlackList} or {dict} 黑名单数据
 * @param callback
 */
var newAndSave = function(backList, callback){
    if(backList instanceof BlackList){
        backList.save(callback);
    }else{
        var m = new BlackList(backList);
        m.save(callback);
    }
}
/**
 * 禁用Ip访问一小时
 * @param ip {String}
 * @param callback
 */
var newAndSaveOneHourTempForbidden = function(ip, callback){
    var expireTime = Date.now() + 1000*60*60;
    newAndSaveTempForbidden(ip,expireTime, callback);
}
/**
 * 禁用一天
 * @param ip {String}
 * @param callback
 */
var newAndSaveOneDayTempForbidden = function(ip, callback){
    var expireTime = Date.now() + 1000*60*60*24;
    newAndSaveTempForbidden(ip, expireTime, callback);
}
/**
 * 新建临时黑名单
 * @param ip {String}
 * @param expireTime {Number} 到期时间
 * @param callback
 */
var newAndSaveTempForbidden = function(ip, expireTime,callback){
    var blackList = new BlackList({ip:ip, expireTime:expireTime, forbiddenDegree:1});
    newAndSave(blackList, callback);
}
/**
 * 新建并保存永久黑名单
 * @param ip
 * @param callback
 */
var newAndSaveForeverForbidden = function(ip, callback){
    var blackList = new BlackList({ip:ip, forbiddenDegree:2});
    newAndSave(blackList, callback);
}
/**
 * 判断是否在黑名单中
 * @param ip {String} Ip地址
 * @param callback
 */
var isInBlackList = function(ip, callback){
    getBlackListByIp(ip, function(err, blackList){
        if(err){
            callback(err);
        }else if(blackList){
            var currentDate = Date.now();
            if(blackList.forbiddenDegree ===1 && blackList.expireTime> currentDate){
                removeBlackListByIp(ip, function(err){
                    if(err){
                        callback(err);
                    }else{
                        callback(null, false);
                    }
                })
            }else{
                callback(null, true);
            }
        }else{
            callback(null, false);
        }
    })
}
/**
 * 通过Ip获取黑名单条目
 * @param ip
 * @param callback
 */
var getBlackListByIp = function(ip, callback){
    BlackList.findOne({ip:ip}, callback);
}
/**
 * 根据Ip删除黑名单
 * @param ip
 * @param callback
 */
var removeBlackListByIp = function(ip, callback){
    getBlackListByIp(ip, function(err, blackList){
        if(err){
            callback(err);
        }else if(blackList){
            blackList.remove(callback);
        }else{
            callback(null,null);
        }
    })
}
exports.newAndSave = newAndSave;
exports.isInBlackList = isInBlackList;
exports.getBlackListByIp = getBlackListByIp;
exports.removeBlackListByIp = removeBlackListByIp;
exports.newAndSaveOneHourTempForbidden = newAndSaveOneHourTempForbidden;
exports.newAndSaveOneDayTempForbidden = newAndSaveOneDayTempForbidden;
exports.newAndSaveForeverForbidden = newAndSaveForeverForbidden;
exports.newAndSaveTempForbidden = newAndSaveTempForbidden;

中间件详情:

/**
 * Created by YCXJ-wanglihui on 2014/5/28.
 */
'use strict';
var BlackListProxy = require('../../proxy').BlackListPorxy;
var IpAnswerLogProxy = require('../../proxy').IpAnswerLogProxy;
var EventProxy = require('eventproxy');
/**
 * 判断是否需要将Ip移动至黑名单中
 * @param req
 * @param res
 * @param next
 */
var isNeedMoveToBlackList = function(req, res, next){
    var ip = req.ip;
    //判断是否在黑名单中
    requireNotInBlackList(req, res, function(){
        var ep = new EventProxy();
        ep.fail(next);
        ep.all('minuteCount', 'hourCount', 'dayCount', function(minuteCount, hourCount, dayCount){
            if(minuteCount > 10){
                BlackListProxy.newAndSaveOneHourTempForbidden(ip, function(err, blackList){
                    if(err){
                        return next(err);
                    }else{
                        return res.send('提交过于频繁,1小时后重试!');
                    }
                });
            }else if(hourCount > 100){
                BlackListProxy.newAndSaveOneDayTempForbidden(ip, function(err, blackList){
                    if(err){
                        return next(err);
                    }else{
                        return res.send('提交过于频繁,1天后重试!');
                    }
                })
            }else if(dayCount > 1000){
                BlackListProxy.newAndSaveOneDayTempForbidden(ip, function(err, blackList){
                    if(err){
                        return next(err);
                    }else{
                        return res.send('提交过于频繁,1天后重试!');
                    }
                })
            }else{
                return next();
            }
        })
        IpAnswerLogProxy.countOneMinuteAnswer(ip,ep.done('minuteCount'));
        IpAnswerLogProxy.countOneHourAnswer(ip, ep.done('hourCount'));
        IpAnswerLogProxy.countOneDayAnswer(ip, ep.done('dayCount'));
    });
}
/**
 * 中间件 要求Ip不在黑名单中
 * @param req
 * @param res
 * @param next
 */
var requireNotInBlackList = function(req, res, next){
    var ip = req.ip;
    BlackListProxy.isInBlackList(ip, function(err, result){
        if(err){
            next(err);
        }else if(result){
            return res.send('您的Ip禁止提交,如有疑问请联系lihui.wang@tulingdao.com');
        }else{
            next();
        }
    })
}
exports.isNeedMoveToBlackList = isNeedMoveToBlackList;
exports.requireNotInBlackList = requireNotInBlackList;

在路由中使用:

//网页提交接口
router.post('/create', middleware.isNeedMoveToBlackList, paperAnswers.create);
NodeJs 相关文章推荐
Nodejs学习笔记之测试驱动
Apr 16 NodeJs
NodeJS连接MongoDB数据库时报错的快速解决方法
May 13 NodeJs
基于NodeJS+MongoDB+AngularJS+Bootstrap开发书店案例分析
Jan 12 NodeJs
nodejs个人博客开发第二步 入口文件
Apr 12 NodeJs
详解nodejs微信jssdk后端接口
May 25 NodeJs
NodeJS链接MySql数据库的操作方法
Jun 27 NodeJs
nodejs密码加密中生成随机数的实例代码
Jul 17 NodeJs
NodeJS使用七牛云存储上传文件的方法
Jul 24 NodeJs
NodeJS实现视频转码的示例代码
Nov 18 NodeJs
NodeJs项目中关闭ESLint的方法
Aug 09 NodeJs
Nodejs文件上传、监听上传进度的代码
Mar 27 NodeJs
NodeJS和浏览器中this关键字的不同之处
Mar 03 NodeJs
nodejs分页类代码分享
Jun 17 #NodeJs
nodejs npm包管理的配置方法及常用命令介绍
Jun 05 #NodeJs
nodejs npm install全局安装和本地安装的区别
Jun 05 #NodeJs
nodejs文件操作模块FS(File System)常用函数简明总结
Jun 05 #NodeJs
使用forever管理nodejs应用教程
Jun 03 #NodeJs
使用upstart把nodejs应用封装为系统服务实例
Jun 01 #NodeJs
nodejs获取本机内网和外网ip地址的实现代码
Jun 01 #NodeJs
You might like
精通php的十大要点(上)
2009/02/04 PHP
PHP通过内置函数memory_get_usage()获取内存使用情况
2014/11/20 PHP
php实现对两个数组进行减法操作的方法
2015/04/17 PHP
phpQuery采集网页实现代码实例
2020/04/02 PHP
Nodejs异步回调的优雅处理方法
2014/09/25 NodeJs
深入理解JavaScript系列(42):设计模式之原型模式详解
2015/03/04 Javascript
jquery实现手机号码选号的方法
2015/07/31 Javascript
Bootstrap实现圆角、圆形头像和响应式图片
2016/12/14 Javascript
深入理解jquery的$.extend()、$.fn和$.fn.extend()
2017/07/08 jQuery
基于vue 动态加载图片src的解决方法
2018/02/05 Javascript
解决Vue中mounted钩子函数获取节点高度出错问题
2018/05/18 Javascript
关于Vue源码vm.$watch()内部原理详解
2019/04/26 Javascript
详解微信小程序开发(项目从零开始)
2019/06/06 Javascript
JavaScript Event Loop相关原理解析
2020/06/10 Javascript
TypeScript 引用资源文件后提示找不到的异常处理技巧
2020/07/15 Javascript
[02:36]DOTA2英雄基础教程 帕格纳
2014/01/20 DOTA
[42:50]NB vs VP 2018国际邀请赛小组赛BO2 第二场 8.18
2018/08/19 DOTA
python实现简单socket通信的方法
2016/04/19 Python
利用信号如何监控Django模型对象字段值的变化详解
2017/11/27 Python
Python中一般处理中文的几种方法
2019/03/06 Python
解决Djang2.0.1中的reverse导入失败的问题
2019/08/16 Python
CSS3实现可翻转的hover效果
2018/05/23 HTML / CSS
Servlet都有哪些方法?主要作用是什么?
2014/03/04 面试题
篝火晚会策划方案
2014/05/16 职场文书
大学生心理活动总结
2014/07/04 职场文书
小学秋季运动会报道稿
2014/09/30 职场文书
党的群众路线对照检查材料思想汇报(学校)
2014/10/04 职场文书
2014年少先队工作总结
2014/12/03 职场文书
努力工作保证书
2015/02/28 职场文书
村官个人总结范文
2015/03/03 职场文书
手机销售员岗位职责
2015/04/11 职场文书
有关花店创业的计划书模板
2019/08/27 职场文书
用Python写一个简易版弹球游戏
2021/04/13 Python
Pytorch distributed 多卡并行载入模型操作
2021/06/05 Python
python tqdm用法及实例详解
2021/06/16 Python
SQL Server使用T-SQL语句批处理
2022/05/20 SQL Server