Authored by 郭成尧

ip-white-list

@@ -159,6 +159,8 @@ try { @@ -159,6 +159,8 @@ try {
159 app.use(require('./doraemon/middleware/limiter')); 159 app.use(require('./doraemon/middleware/limiter'));
160 } 160 }
161 161
  162 + app.use(require('./doraemon/middleware/limiter'));
  163 +
162 if (app.locals.devEnv) { 164 if (app.locals.devEnv) {
163 app.use(devtools()); 165 app.use(devtools());
164 } 166 }
@@ -13,14 +13,15 @@ const isTest = process.env.NODE_ENV === 'test'; @@ -13,14 +13,15 @@ const isTest = process.env.NODE_ENV === 'test';
13 13
14 const domains = { 14 const domains = {
15 15
16 - api: 'http://api.yoho.cn/',  
17 - service: 'http://service.yoho.cn/',  
18 - liveApi: 'http://testapi.live.yohops.com:9999/',  
19 - singleApi: 'http://api-test3.yohops.com:9999/', 16 + // api: 'http://api.yoho.cn/',
  17 + // service: 'http://service.yoho.cn/',
  18 + // liveApi: 'http://testapi.live.yohops.com:9999/',
  19 + // singleApi: 'http://api-test3.yohops.com:9999/',
20 20
21 // gray 21 // gray
22 - // api: 'http://apigray.yoho.cn/',  
23 - // service: 'http://apigray.yoho.cn/', 22 + api: 'http://apigray.yoho.cn/',
  23 + service: 'http://apigray.yoho.cn/',
  24 +
24 // platformApi: 'http://172.16.6.210:8088/', 25 // platformApi: 'http://172.16.6.210:8088/',
25 26
26 27
@@ -4,7 +4,9 @@ const _ = require('lodash'); @@ -4,7 +4,9 @@ const _ = require('lodash');
4 const logger = global.yoho.logger; 4 const logger = global.yoho.logger;
5 const ip = require('./rules/ip-list'); 5 const ip = require('./rules/ip-list');
6 const userAgent = require('./rules/useragent'); 6 const userAgent = require('./rules/useragent');
  7 +const ipWhiteList = require('./rules/ip-white-list');
7 const qpsLimiter = require('./rules/qps-limit'); 8 const qpsLimiter = require('./rules/qps-limit');
  9 +const co = Promise.coroutine;
8 10
9 // const asynchronous = require('./rules/asynchronous'); 11 // const asynchronous = require('./rules/asynchronous');
10 // const fakerLimiter = require('./rules/faker-limit'); 12 // const fakerLimiter = require('./rules/faker-limit');
@@ -58,19 +60,44 @@ const limiter = (rule, policy, context) => { @@ -58,19 +60,44 @@ const limiter = (rule, policy, context) => {
58 return rule(context, policy); 60 return rule(context, policy);
59 }; 61 };
60 62
61 -module.exports = (req, res, next) => { 63 +// 排除条件:ip白名单/路径白名单/异步请求/登录用户
  64 +const _excluded = (req) => {
62 let remoteIp = req.yoho.clientIp || ''; 65 let remoteIp = req.yoho.clientIp || '';
  66 + let remoteIpSegment = `${remoteIp.split('.').slice(0, 2).join('.')}.`;
  67 +
  68 + return co(function* () {
  69 + let cacheIpWhiteList = yield ipWhiteList();
  70 +
  71 + return Boolean(
  72 + _.includes(cacheIpWhiteList, remoteIp) ||
  73 + _.includes(IP_WHITE_LIST, remoteIp) ||
  74 + _.includes(IP_WHITE_SEGMENT, remoteIpSegment) ||
  75 + _.includes(PATH_WHITE_LIST, req.path) ||
  76 + req.xhr ||
  77 + !_.isEmpty(_.get(req, 'user.uid'))
  78 + );
  79 + })();
  80 +};
63 81
64 - // 排除条件:ip白名单/路径白名单/异步请求/登录用户  
65 - const excluded = _.includes(IP_WHITE_LIST, remoteIp) ||  
66 - _.includes(IP_WHITE_SEGMENT, `${remoteIp.split('.').slice(0, 2).join('.')}.`) ||  
67 - _.includes(PATH_WHITE_LIST, req.path) || req.xhr || !_.isEmpty(_.get(req, 'user.uid')); 82 +module.exports = (req, res, next) => {
  83 + const remoteIp = req.yoho.clientIp || '';
68 const enabled = !_.get(req.app.locals, 'wap.sys.noLimiter'); 84 const enabled = !_.get(req.app.locals, 'wap.sys.noLimiter');
69 85
70 - logger.debug(`request remote ip: ${remoteIp}; excluded: ${excluded}; enabled: ${enabled}`); 86 + // 开关为关或者未获取到remoteIp,放行
  87 + if (!enabled || !remoteIp) {
  88 + logger.debug(`request remote ip: ${remoteIp}; enabled: ${enabled}`);
  89 + return next();
  90 + }
71 91
72 - // 判断获取remoteIp成功,并且开关未关闭  
73 - if (enabled && remoteIp && !excluded) { 92 + co(function* () {
  93 + let excluded = yield _excluded(req);
  94 +
  95 + logger.debug(`request remote ip: ${remoteIp}; excluded: ${excluded}; enabled: ${enabled}`);
  96 +
  97 + // 白名单,放行
  98 + if (excluded) {
  99 + return next();
  100 + }
74 const context = { 101 const context = {
75 req: req, 102 req: req,
76 res: res, 103 res: res,
@@ -78,42 +105,39 @@ module.exports = (req, res, next) => { @@ -78,42 +105,39 @@ module.exports = (req, res, next) => {
78 remoteIp: remoteIp 105 remoteIp: remoteIp
79 }; 106 };
80 107
81 - Promise.all([ 108 + let results = yield Promise.all([
82 limiter(userAgent, captchaPolicy, context), 109 limiter(userAgent, captchaPolicy, context),
83 limiter(ip, captchaPolicy, context), 110 limiter(ip, captchaPolicy, context),
84 limiter(qpsLimiter, captchaPolicy, context) 111 limiter(qpsLimiter, captchaPolicy, context)
85 112
86 // limiter(asynchronous, captchaPolicy, context) 113 // limiter(asynchronous, captchaPolicy, context)
87 // limiter(fakerLimiter, reporterPolicy, context) 114 // limiter(fakerLimiter, reporterPolicy, context)
88 - ]).then((results) => {  
89 - let allPass = true, exclusion = false, policy = null;  
90 -  
91 - logger.debug('limiter result: ' + JSON.stringify(results));  
92 -  
93 - _.forEach(results, (result) => {  
94 - if (typeof result === 'object' && !exclusion) {  
95 - exclusion = result.exclusion;  
96 - }  
97 -  
98 - if (typeof result === 'function') {  
99 - allPass = false;  
100 - policy = result;  
101 - }  
102 - });  
103 -  
104 - if (exclusion) {  
105 - return next();  
106 - } else if (!allPass && policy) {  
107 - policy(req, res, next);  
108 - } else {  
109 - return next(); 115 + ]);
  116 +
  117 + let allPass = true, exclusion = false, policy = null;
  118 +
  119 + logger.debug('limiter result: ' + JSON.stringify(results));
  120 +
  121 + _.forEach(results, (result) => {
  122 + if (typeof result === 'object' && !exclusion) {
  123 + exclusion = result.exclusion;
110 } 124 }
111 125
112 - }).catch((err) => {  
113 - logger.error(err);  
114 - return next(); 126 + if (typeof result === 'function') {
  127 + allPass = false;
  128 + policy = result;
  129 + }
115 }); 130 });
116 - } else { 131 +
  132 + if (exclusion) {
  133 + return next();
  134 + } else if (!allPass && policy) {
  135 + policy(req, res, next);
  136 + } else {
  137 + return next();
  138 + }
  139 + })().catch(err => {
  140 + logger.error(err);
117 return next(); 141 return next();
118 - } 142 + });
119 }; 143 };
  1 +const co = Promise.coroutine;
  2 +const cache = global.yoho.cache.master;
  3 +const WHITE_LIST_KEY = 'whitelist:ips';
  4 +
  5 +module.exports = () => {
  6 + return co(function* () {
  7 + let listFromCache = yield cache.getAsync(WHITE_LIST_KEY);
  8 +
  9 + return Promise.resolve(JSON.parse(listFromCache) || []);
  10 + })();
  11 +};