2016-08-05 104 views
0

我使用ExpressJS中间件来检查数据库中的用户IP,并在最后一小时有超过7次失败登录时停止响应用户,我在数据库连接之前检查'/'是否为垃圾邮件数据库如果一切正常。但事实证明,虽然中间件正在访问数据库并在回调中执行检查,但第一个else中的代码仍在运行。这里是我的中间件:回调阻止线程

// check for failed logins from this ip in db 
// if allowed number exceeded - stop responding 
app.use(function (req, res, next) { 
if(req._parsedUrl.pathname === '/') { 
    MongoClient.connect(databaseUri || 'mongodb://localhost:27017/dev', function (err, db) { 
     assert.equal(err, null); 
     var failedLogins = db.collection('FailedLogins'); 
     failedLogins.find({ip: req._remoteAddress}).toArray(function (err, results) { 
      assert.equal(err, null); 
      console.log('db check'); 
      // if ip is in FailedLogins collection 
      if (results.length) { 
       // if there are more than 7 logins and they haven't expired 
       if (results[0].failedLoginsNum >= 7 && parseInt(results[0].expiration) >= parseInt(Date.now())) { 
        res.end(); 
       } else { 
        next(); 
       } 
      } else { 
       next(); 
      } 
     }); 
    }); 
} else { 
    console.log('next'); 
    next(); 
} 
}); 

这是控制台输出:

db check 
GET/200 20.117 ms - - 
next 
GET /favicon.ico 200 207.559 ms - 1353 

回答

1

这是正常现象,因为不是db建立连接,并找到查询完成第二个请求先前接收。

首先你不想在每个请求上创建新的连接,这是一个不好的做法。

考虑下面的代码:

dbProvider.js

'use strict'; 

const MongoClient = require('mongodb').MongoClient; 
const CONNECTION_PATH = 'mongodb://localhost:27017/dev'; 

module.exports.init = cb => { 
    MongoClient.connect(CONNECTION_PATH, (err, db) => { 
    module.exports.db = db; 
    cb(err, db); 
    }); 
}; 

index.js

'use strict'; 

const express = require('express'); 
const app = express(); 

const dbProvider = require('./dbProvider'); 
const PORT = 8888; 

dbProvider.init((err, db) => { 
    if(err) { 
    console.error(err); 
    process.exit(1); 
    } 

    app.listen(PORT,() => console.log(`Listening on port ${PORT}`)); 
}); 

在index.js我们等到建立连接,然后才监听HTTP请求。 下一步是登录,所以如果你想限制登录尝试,我建议使用简单的中间件。

index.js修改

'use strict'; 

const express = require('express'); 
const app = express(); 

const dbProvider = require('./dbProvider'); 
const PORT = 8888; 

dbProvider.init((err, db) => { 
    if(err) { 
    console.error(err); 
    process.exit(1); 
    } 

    app.listen(PORT,() => console.log(`Listening on port ${PORT}`)); 
}); 

// middlewares 

function checkAuth(req, res, next) { 
    // here check if userId in cookie and match to db record or check token 
    if (req.authenticated()) { 
    return next(); 
    } else { 
    return res.send(401); // Respond "Unauthorized" 
    } 
} 

function checkLoginAttempts(req, res, next) { 
    let failedLogins = dbProvider.db.collection('FailedLogins'); 
    failedLogins.find({ip: req._remoteAddress}).toArray(function (err, results) { 
    if(err) { 
     console.error(err); 
     return res.status(500).end(); 
    } 
    console.log('db check'); 

    if(!results.length) return next(); 

    // if ip is in FailedLogins collection 
    // if there are more than 7 logins and they haven't expired 
    if (results[0].failedLoginsNum >= 7 && parseInt(results[0].expiration) >= parseInt(Date.now())) { 
     res.status(401).send('The maximum number of login attempts has been reached. Please try again in 1 hour.'); 
    } else { 
     next(); 
    } 
    }); 
} 

// routes 

app.use('/yourLoginEndPoint', checkLoginAttempts, (req, res) => { 
    // login process, set userId as cookie value or create token 
}); 

app.use('/anyOtherEndPoint', checkAuth, (req, res) => { 
    // here you sure that user is authenticated 
}); 

如果有任何问题,让我知道

+0

感谢,您的实现看起来那么多比我好,我就用它作为指导试图解决的一塌糊涂我已经完成) – snowfinch27

+0

欢迎您使用广泛使用的身份验证库[passportJs](http://passportjs.org/),它支持许多Oauth策略,如Google,Facebook等。对于mongoDb,有一个[mongoose](http://mongoosejs.com/)库,它有更多的功能,比如创建模式,预先保存钩子等。 –

+0

谢谢,绝对会检查出来 – snowfinch27