2012-12-18 38 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