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