2016-08-05 102 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