Blame view

doraemon/middleware/limiter/index.js 2.82 KB
姜枫 authored
1 2 3 4 5 6
'use strict';

const _ = require('lodash');
const logger = global.yoho.logger;
const ip = require('./rules/ip-list');
const userAgent = require('./rules/useragent');
郭成尧 authored
7
const ipWhiteList = require('./rules/ip-white-list');
yyq authored
8
const pathWhiteList = require('./rules/path-white-list');
姜枫 authored
9
const qpsLimiter = require('./rules/qps-limit');
郭成尧 authored
10
const co = Promise.coroutine;
郝肖肖 authored
11 12 13

// const asynchronous = require('./rules/asynchronous');
// const fakerLimiter = require('./rules/faker-limit');
姜枫 authored
14 15
const captchaPolicy = require('./policies/captcha');
郝肖肖 authored
16 17
// const reporterPolicy = require('./policies/reporter');
姜枫 authored
18 19 20 21
const limiter = (rule, policy, context) => {
    return rule(context, policy);
};
郭成尧 authored
22 23
// 排除条件:ip白名单/路径白名单/异步请求/登录用户
const _excluded = (req) => {
毕凯 authored
24
    let remoteIp = req.yoho.clientIp || '';
郭成尧 authored
25 26

    return co(function* () {
yyq authored
27
        let atIPWhiteList = yield ipWhiteList(remoteIp);
郭成尧 authored
28 29

        return Boolean(
yyq authored
30
            atIPWhiteList ||
yyq authored
31
            _.includes(pathWhiteList(), req.path) ||
郭成尧 authored
32 33 34 35 36
            req.xhr ||
            !_.isEmpty(_.get(req, 'user.uid'))
        );
    })();
};
毕凯 authored
37
郭成尧 authored
38 39
module.exports = (req, res, next) => {
    const remoteIp = req.yoho.clientIp || '';
郝肖肖 authored
40
    const enabled = !_.get(req.app.locals, 'wap.sys.noLimiter');
郝肖肖 authored
41
郭成尧 authored
42 43 44 45 46
    // 开关为关或者未获取到remoteIp,放行
    if (!enabled || !remoteIp) {
        logger.debug(`request remote ip: ${remoteIp}; enabled: ${enabled}`);
        return next();
    }
姜枫 authored
47
郭成尧 authored
48 49
    co(function* () {
        let excluded = yield _excluded(req);
姜枫 authored
50
郭成尧 authored
51 52 53 54 55 56
        logger.debug(`request remote ip: ${remoteIp}; excluded: ${excluded}; enabled: ${enabled}`);

        // 白名单,放行
        if (excluded) {
            return next();
        }
姜枫 authored
57 58 59 60 61 62 63
        const context = {
            req: req,
            res: res,
            next: next,
            remoteIp: remoteIp
        };
郭成尧 authored
64
        let results = yield Promise.all([
姜枫 authored
65 66
            limiter(userAgent, captchaPolicy, context),
            limiter(ip, captchaPolicy, context),
郝肖肖 authored
67
            limiter(qpsLimiter, captchaPolicy, context)
毕凯 authored
68
郝肖肖 authored
69
            // limiter(asynchronous, captchaPolicy, context)
毕凯 authored
70
            // limiter(fakerLimiter, reporterPolicy, context)
郭成尧 authored
71 72 73 74 75 76 77 78 79
        ]);

        let allPass = true, exclusion = false, policy = null;

        logger.debug('limiter result: ' + JSON.stringify(results));

        _.forEach(results, (result) => {
            if (typeof result === 'object' && !exclusion) {
                exclusion = result.exclusion;
姜枫 authored
80 81
            }
郭成尧 authored
82 83 84 85
            if (typeof result === 'function') {
                allPass = false;
                policy = result;
            }
姜枫 authored
86
        });
郭成尧 authored
87 88 89 90 91 92 93 94 95 96

        if (exclusion) {
            return next();
        } else if (!allPass && policy) {
            policy(req, res, next);
        } else {
            return next();
        }
    })().catch(err => {
        logger.error(err);
姜枫 authored
97
        return next();
郭成尧 authored
98
    });
姜枫 authored
99
};