黑名单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禁止提交,如有疑问请联系[email protected]'); }else{ next(); } }) } exports.isNeedMoveToBlackList = isNeedMoveToBlackList; exports.requireNotInBlackList = requireNotInBlackList;
在路由中使用:
//网页提交接口 router.post('/create', middleware.isNeedMoveToBlackList, paperAnswers.create);