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中简单实现Javascript Promise机制的实例
Dec 06 NodeJs
Nodejs如何搭建Web服务器
Mar 28 NodeJs
nodejs获取微信小程序带参数二维码实现代码
Apr 12 NodeJs
NodeJs中express框架的send()方法简介
Jun 20 NodeJs
nodejs async异步常用函数总结(推荐)
Nov 17 NodeJs
nodejs连接mysql数据库及基本知识点详解
Mar 20 NodeJs
详解nodejs通过响应回写的方式渲染页面资源
Apr 07 NodeJs
nodeJS模块简单用法示例
Apr 21 NodeJs
详解从NodeJS搭建中间层再谈前后端分离
Nov 13 NodeJs
详解nodejs http请求相关总结
Mar 31 NodeJs
nodejs提示:cross-device link not permitted, rename错误的解决方法
Jun 10 NodeJs
使用nodeJS中的fs模块对文件及目录进行读写,删除,追加,等操作详解
Feb 06 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
法国:浪漫之都的咖啡文化
2021/03/03 咖啡文化
IIS7.X配置PHP运行环境小结
2011/06/09 PHP
PHP ? EasyUI DataGrid 资料存的方式介绍
2012/11/07 PHP
PHP的cURL库简介及使用示例
2015/02/06 PHP
php通过asort()给关联数组按照值排序的方法
2015/03/18 PHP
谈谈php对接芝麻信用踩的坑
2016/12/01 PHP
PHP实现的多维数组排序算法分析
2018/02/10 PHP
PHP基于curl实现模拟微信浏览器打开微信链接的方法示例
2019/02/15 PHP
Javascript 汉字字节判断
2009/08/01 Javascript
javascript 广告后加载,加载完页面再加载广告
2010/11/25 Javascript
解析javascript系统错误:-1072896658的解决办法
2013/07/08 Javascript
28个常用JavaScript方法集锦
2015/01/14 Javascript
jQuery与getJson结合的用法实例
2015/08/07 Javascript
Jquery全屏相册插件zoomvisualizer具有调节放大与缩小功能
2015/11/02 Javascript
jQuery实现左侧导航模块的显示与隐藏效果
2016/07/04 Javascript
javascript弹出带文字信息的提示框效果
2016/07/19 Javascript
js监听键盘事件的方法_原生和jquery的区别详解
2016/10/10 Javascript
JS中作用域和变量提升(hoisting)的深入理解
2016/10/31 Javascript
javascript完美实现给定日期返回上月日期的方法
2017/06/15 Javascript
JS操作时间 - UNIX时间戳的简单介绍(必看篇)
2017/08/16 Javascript
Vue 按键修饰符处理事件的方法
2018/05/04 Javascript
详解KOA2如何手写中间件(装饰器模式)
2018/10/11 Javascript
Angular2 自定义表单验证器的实现方法
2018/12/14 Javascript
vue项目强制清除页面缓存的例子
2019/11/06 Javascript
javascript实现倒计时提示框
2021/03/02 Javascript
[01:00:54]TI4正赛第二日开场
2014/07/20 DOTA
python创建和删除目录的方法
2015/04/29 Python
简析Python的闭包和装饰器
2016/02/26 Python
Python使用 Beanstalkd 做异步任务处理的方法
2018/04/24 Python
Python使用googletrans报错的解决方法
2018/09/25 Python
python标准库OS模块函数列表与实例全解
2020/03/10 Python
日本化妆品植村秀俄罗斯官方网站:Shu Uemura俄罗斯
2020/02/01 全球购物
六月份红领巾广播稿
2014/02/03 职场文书
Django REST framework 限流功能的使用
2021/06/24 Python
将MySQL的表数据全量导入clichhouse库中
2022/03/21 MySQL
MySQL 原理优化之Group By的优化技巧
2022/08/14 MySQL