2012-12-18 75 views
8

我正在爲某些Node.js框架背後的一些理論和約定而掙扎。我是Node.js的新手。我試圖建立一個場景,我有一個MVC框架,我定義了一組控制器來完成基本的休息功能,而我的一些控制器路由需要認證。如果您沒有通過身份驗證,它應該會將您發送到登錄頁面,但在您登錄後,會將您發送回您以前請求的頁面。我已經看了一大堆教程,我已經看了一些關於StackOverflow的問題,但我認爲問題在於某些東西只是不點擊而已。我希望你們中的一個能夠向我解釋發生了什麼的一些理論,也許可以指出我的問題是正確的。我的代碼如下。我真正的問題是我不太瞭解這個下一個()範例。也許我甚至全都做錯了,並以錯誤的方式思考它。也許你可以讓我介紹一些好的想法。Node.js理論 - Node.js,Express.js,Passport.js

編輯:

======

我找到了解決辦法。稍後我會回答我的問題,以供任何可能希望獲得一些信息並解決該問題的人使用。

- Server.js

/** 
* Clancy server implementation (using Express) 
*/ 
require('console-trace')({ 
    always: true, 
    right: true, 
    colors: true 
}) 

/** 
* Include our server's needed objects. 
**/ 
var express = require('express'); 
var _ = require('underscore'); 
var cons = require('consolidate'); 
passport = require('passport'), 
LocalStrategy = require('passport-local').Strategy; 
var db = require('./lib/db'); 
var colors = require('colors'); 
var Users = db.users; 
var People = require('./controllers/People'); 
var Login = require('./controllers/Login'); 

/** 
* This provides our MVC context object 
**/ 
var app = express(); 


/** 
* This is our router definition for the server 
**/ 
app.engine('html', cons.underscore); 

// set .html as the default extension 
app.set('view engine', 'html'); 
app.set('views', __dirname + '/views'); 

/** 
* Set up the server to allow static content, cookies, session, and 
* parsing the server. Also, we initialize authentication and our 
* routing mechanism. 
* 
*/ 

app.configure(function() { 
    app.use('/static', express.static(__dirname + "/webapp")); 
    app.use(express.cookieParser()); 
    app.use(express.bodyParser()); 
    app.use(express.session({ 
     secret: 'keyboard cat' 
    })); 
    app.use(passport.initialize()); 
    app.use(passport.session()); 
    app.use(app.router); 
}); 

/** 
* This lets authentication know how it should store 
* and grab users from a request to pass to a mapping 
* function. 
*/ 
passport.serializeUser(function (user, done) { 
    done(null, user._id); 
}); 

passport.deserializeUser(function (id, done) { 
    Users.findOne({ 
     _id: db.bson.ObjectID(id) 
    }, function (err, user) { 
     done(err, user); 
    }); 
}); 

/** 
* This sets up which authentication strategies we support. 
* as of right now, LocalStrategy (our own username/password) 
* is all we support. 
* 
*/ 
passport.use(new LocalStrategy(

function (username, password, done) { 
    Users.findOne({ 
     username: username 
    }, function (err, user) { 
     if (err) { 
      return done(err); 
     } 
     if (!user) { 
      return done(null, false, { 
       message: 'Incorrect username.' 
      }); 
     } 
     if (!(user.password == password)) { 
      return done(null, false, { 
       message: 'Incorrect password.' 
      }); 
     } 
     console.info(user.password + " " + password.yellow); 
     console.info(!(user.password == password).yellow); 
     console.info(user._id); 
     return done(null, user); 
    }); 
})); 

/** 
* Path mapping 
*/ 

// Index mapping 
app.get('/', function (req, resp) { 
    resp.render('index', { 
     title: "Welcome!" 
    }); 
}); 

// Allow login, and set up the dependency for passport. 
Login.setPassport(passport); 
app.get("/login", Login.loginForm); 
app.get("/login/error", Login.loginForm); 
app.post('/login', passport.authenticate('local', function (req, res, next) { 
    passport.authenticate('local', function (err, user, info) { 
     // This is the default destination upon successful login. 
     var redirectUrl = '/people'; 

     if (err) { 
      return next(err); 
     } 
     if (!user) { 
      return res.redirect('/'); 
     } 

     // If we have previously stored a redirectUrl, use that, 
     // otherwise, use the default. 
     if (req.session.redirectUrl) { 
      redirectUrl = req.session.redirectUrl; 
      req.session.redirectUrl = null; 
     } 
     req.logIn(user, function (err) { 
      if (err) { 
       return next(err); 
      } 
     }); 
     res.redirect(redirectUrl); 
    })(req, res, next); 
})); 

app.get('/logout', Login.logout); 

// People Controller has a dependency on the Passport library 
People.setPassport(passport); 

// These are our definitions for paths the People Controller can handle. 
app.get("/people", People.list); 
app.get("/people/:id", People.get); 

// These are the error handler mappings. 
app.use(function (req, res, next) { 
    // the status option, or res.statusCode = 404 
    // are equivalent, however with the option we 
    // get the "status" local available as well 
    res.render('404', { 
     status: 404, 
     url: req.url 
    }); 
}); 

app.use(function (err, req, res, next) { 
    // we may use properties of the error object 
    // here and next(err) appropriately, or if 
    // we possibly recovered from the error, simply next(). 
    console.error(("ERROR: " + err.toString()).red); 
    res.render('500', { 
     status: err.status || 500, 
     error: err 
    }); 
}); 
app.listen(3000); 
console.info('The Clancy server is listening on port: 3000'.green); 

- 人民控制器

/** 
* People Controller 
*/ 
var db = require('../lib/db'); 
var auth = require('../lib/authUtils'); 
/** 
* People constructor. 
* =================== 
* The people constructor has dependencies on the database, 
* and on the Passport middleware. The db object doesn't 
* care about maintaining state, so we can just include that 
* here, however the Passport plugin needs to have all of the 
* stuff the server defines. So, it's passed in. 
*/ 
function People(){ 
    var passport; 
} 
People.prototype = { 
     list: function(req, resp){ 
      auth.ensureAuth(req, resp); 
      console.info("user info: " + user._id); 
      resp.render('index', { 
       title: "User", 
       users: [1,2,3] 
      }); 
     }, 
     get: function(req, resp){ 

      console.log('> get person' + req.params.id); 

      db.users.find({_id: db.bson.ObjectID(id)}, function(err, users){ 
       if(err || !users) console.log("No user found"); 
       resp.send(users); 
      }); 
     }, 
     setPassport: function(pass){ 
      this.passport = pass; 
     }, 
     getPassport: function(){ 
      return this.passport; 
     } 
} 

module.exports = new People(); 

- 登錄控制器

/** 
* People Controller 
*/ 

/** 
* Login constructor. 
* =================== 
* The Login constructor has dependencies on the Passport middleware. 
* The db object doesn't care about maintaining state, so we can just 
* include that here, however the Passport plugin needs to have all 
* of the stuff the server defines. So, it's passed in. 
*/ 
function Login(){ 
    var passport; 
} 
var l = Login.prototype; 
Login.prototype = { 
     loginForm: function(req, resp){ 
      var url = require('url').parse(req.url, true); 
      console.info('url string: ' + url.pathname.yellow); 
      if(url.pathname === '/login/error') 
      { 
       resp.render('login', { 
        title: "Login to FormPickle.com", 
        message: "Your username or password was incorrect." 
       }); 
      } 
      console.info('Trying to login'.yellow); 
      resp.render('login', { 
       title: "Login to FormPickle.com", 
       message: "" 
      }); 
     }, 
     setPassport: function(pass){ 
      l.passport = pass; 
     }, 
     getPassport: function(){ 
      return l.passport; 
     }, 
     logout: function(req, resp){ 
      req.logout(); 

      resp.render('logout'); 
     } 
} 

module.exports = new Login(); 

- DB中間件

/** 
* DB 
*/ 

var databaseURI = "localhost:27017/clancy"; 
var collections = ["users", "forms"]; 
var db = require("mongojs").connect(databaseURI, collections); 

module.exports = db; 

- AuthUtils.js

/*** 
* Define a middleware function for authenticated routes to store the original URL 
* 
*/ 
function Auth(){ 

}; 

Auth.prototype = { 
    ensureAuth: ensureAuthenticated(req, resp, next) 
} 
var ensureAuthenticated = function (req, res, next) { 
    if (req.isAuthenticated()) { return next(); } 

    // If the user is not authenticated, then we will start the authentication 
    // process. Before we do, let's store this originally requested URL in the 
    // session so we know where to return the user later. 

    req.session.redirectUrl = req.url; 

    // Resume normal authentication... 

    logger.info('User is not authenticated.'); 
    req.flash("warn", "You must be logged-in to do that."); 
    res.redirect('/login'); 
} 

module.exports = new Auth(); 

謝謝你們提前。我喜歡StackOverflow上的社區。學習新技術時,你們總是非常棒。

+2

只是一個評論,如果express可以配置爲提供靜態文件並不意味着這是最好的解決方案,您通常使用nginx for這個目的。 –

+0

瞭解。這只是一個初始傳球設置。我稍後將轉換爲靜態內容的HTTP服務器。 –

+0

TJ Holowaychuk使用快速實現MVC [示例](https://github.com/visionmedia/express/tree/master/examples/mvc) – verybadalloc

回答

1

返回next通常爲Connect中間件是。您正在傳遞下一個要執行的函數的引用。中間件的作用就像過濾器,或鏈接列出的層(通過引用類型),在您獲取資源之前,您的函數會調用並遵循,然後執行邏輯,然後決定退出/重定向或轉到下一個中​​間件。中間件可能是身份驗證,例如您正在使用。儘管Passport是一個分離且寫得很好的模塊,但您在這裏實現它作爲中間件(這是正常的),它基本上是一個通過您的ensureAuthenticated函數的認證過濾器:您基本上只是在那裏創建了自己的中間件(Achievement Unlocked) 。在執行路由功能之前,您通常會將所有中間件都放置好。

你定義爲-- DB Middleware什麼不是中間件,從我可以告訴。它看起來更像是一個模塊,你正試圖單獨考慮(這很好)。我會打電話給你的model模塊的開頭。

看起來您的控制器可能會很快失控。我建議研究Routes

我不是在問候的Node.js,Express.js護照和任何方式的專家。js,但我成功地分離了一個部分工作的項目中組織的問題和編碼:https://github.com/Tzvayim/theArk/blob/master/app.js