

 代码如下:
/**
 * 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);
 
