nodejs实现黑名单中间件设计

黑名单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);

(0)

相关推荐

  • 利用NodeJS和PhantomJS抓取网站页面信息以及网站截图

    利用PhantomJS做网页截图经济适用,但其API较少,做其他功能就比较吃力了.例如,其自带的Web Server Mongoose最高只能同时支持10个请求,指望他能独立成为一个服务是不怎么实际的.所以这里需要另一个语言来支撑服务,这里选用NodeJS来完成. 安装PhantomJS 首先,去PhantomJS官网下载对应平台的版本,或者下载源代码自行编译.然后将PhantomJS配置进环境变量,输入 $ phantomjs 如果有反应,那么就可以进行下一步了. 利用PhantomJS进行简

  • 跟我学Nodejs(一)--- Node.js简介及安装开发环境

    学习资料 1.深入浅出Node.js 2.Node.js开发指南 简介(只捡了我觉得重要的) Node.js是让Javascript脱离浏览器运行在服务器的一个平台,不是语言: Node.js采用的Javascript引擎是来自Google Chrome的V8:运行在浏览器外不用考虑头疼的Javascript兼容性问题 采用单线程.异步IO与事件驱动的设计来实现高并发(异步事件也在一定程度上增加了开发和调试的难度): Node.js内建一个HTTP服务器,所以对于网站开发来说是一个好消息:  

  • nodejs分页类代码分享

    分页类,我放在 plugin/Paginate.js 复制代码 代码如下: /** * 分页插件类(缺少每页的显示数,listrows明天写) * @param page {Number} 当前页 * @param pagesize {Number} 每页记录数 * @param total {Number} 总记录数 * @constructor */function Paginate(page, pagesize, total){    if(!page || page <1){      

  • nodejs读取memcache示例分享

    复制代码 代码如下: var memcache = require('memcache')    , http = require('http')    , url = require('url')    , qs = require('querystring')    , memsettings = { port: 2000, host: '10.6.0.6' }    , httpsettings = { port: 3000 }    , cacheObject = {}    , htt

  • nodejs实现黑名单中间件设计

    黑名单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} 黑名

  • koa2 数据api中间件设计模型的实现方法

    假设所有的数据库读取,http api 接口请求都为一个中间件,将中间件当做插件,插入需要获取数据的位置. api.js module.exports = async (ctx, next) => { ctx.share_data.api_data = await axios.get('/api'); await next(); }; db.js module.exports = async (ctx, next) => { ctx.share_data.db_data = await mys

  • nodejs处理图片的中间件node-images详解

    Cross-platform image decoder(png/jpeg/gif) and encoder(png/jpeg) for Node.js node.js轻量级跨平台图像编解码库 var images = require("images"); images("input.jpg") //Load image from file //加载图像文件 .size(400) //Geometric scaling the image to 400 pixels

  • nodejs关于中间件解析

    目录 nodejs 中间件 中间件的编写 中间件的使用 nodejs制作自定义中间件 总结 nodejs 中间件 今天我们来了解一下 nodejs 中间件,中间件可以说是 node 中最重要也是最核心的地方.它最重要的思想便是 洋葱模型 ,从外到内依次执行中间件. 说了半天中间件到底有什么作用呢,在处理服务请求时,我们要进行很多细节的处理,比如解析请求体,报文报头,设置 cookie 等等很多操作,如果每次访问路由都要编写这些繁琐的代码,将会造成代码混乱,你可能连自己的业务逻辑代码都找不到了.

  • 适合前端Vue开发童鞋的跨平台Weex的使用详解

    基于 Vue 技术栈的你如果需要选用一种移动端跨平台框架,是 Weex?React-Native?还是Flutter? 无疑,相对于后两者,因为你现在已有比较熟练的 Vue 基础,如果在其他条件一致的情况,Weex 无疑是最佳选择:但是 Weex 真的适合在实际项目中进行移动端跨平台开发吗?Weex 的开发效率.Weex 的质量是否满足需求? 一.开发环境 在这个 Weex app 开发中,我的开发环境相关配置如下: 工具名称 版本号 Node.js 8.2.1 Npm 5.3.0 Androi

  • 玩转Koa之核心原理分析

    Koa作为下一代Web开发框架,不仅让我们体验到了async/await语法带来同步方式书写异步代码的酸爽,而且本身简洁的特点,更加利于开发者结合业务本身进行扩展. 本文从以下几个方面解读Koa源码: 封装创建应用程序函数 扩展res和req 中间件实现原理 异常处理  一.封装创建应用程序函数 利用NodeJS可以很容易编写一个简单的应用程序: const http = require('http') const server = http.createServer((req, res) =>

  • Java编程rabbitMQ实现消息的收发

    java实现rAMQP,即Advanced Message Queuing Protocol,高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计.消息中间件主要用于组件之间的解耦,消息的发送者无需知道消息使用者的存在,反之亦然. AMQP的主要特征是面向消息.队列.路由(包括点对点和发布/订阅).可靠性.安全. RabbitMQ是一个开源的AMQP实现,服务器端用Erlang语言编写,支持多种客户端,如:Python.Ruby..NET.Java.JMS.C.PHP.Actio

  • SpringBoot webSocket实现发送广播、点对点消息和Android接收

    1.SpringBoot webSocket SpringBoot 使用的websocket 协议,不是标准的websocket协议,使用的是名称叫做STOMP的协议. 1.1 STOMP协议说明 STOMP,Streaming Text Orientated Message Protocol,是流文本定向消息协议,是一种为MOM(Message Oriented Middleware,面向消息的中间件)设计的简单文本协议. 它提供了一个可互操作的连接格式,允许STOMP客户端与任意STOMP消

  • Laravel5权限管理方法详解

    本文实例讲述了Laravel5权限管理的实现方法.分享给大家供大家参考,具体如下: 关于权限管理的思考 最近用laravel设计后台,后台需要有个权限管理.权限管理实质上分为两个部分,首先是认证,然后是权限.认证部分非常好做,就是管理员登录,记录session.这个laravel中也有自带Auth来实现这个.最麻烦就是权限认证. 权限认证本质上就是谁有权限管理什么东西.这里有两个方面的维度,谁,就是用户维度,在用户维度,权限管理的粒度可以是用户一个人,也可以是将用户分组,如果将用户分组,则涉及到

  • SpringBoot与rabbitmq的结合的示例

    消息中间件对于我们系统之间的解耦合,消峰等都有极大的帮助.spring boot 也集成了此部分的内容,集成最为容易的是rabbitmq.今天我们就以rabbitmq为例说明. 老规矩,先看下pom <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <

随机推荐