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禁止提交,如有疑问请联系[email protected]');

  }else{

  next();

  }

  })

  }

  exports.isNeedMoveToBlackList = isNeedMoveToBlackList;

  exports.requireNotInBlackList = requireNotInBlackList;

  在路由中使用:

  

复制代码 代码如下:

  //网页提交接口

  router.post('/create', middleware.isNeedMoveToBlackList, paperAnswers.create);