Node.js theory - Node.js, Express.js, Passport.js



我正在与一些Node.js框架背后的一些理论和约定作斗争。我是Node.js的新手。我正在尝试建立一个场景,在这个场景中,我有一个MVC框架,在这个框架中,我定义了一组执行基本休息功能的控制器,并且我的一些控制器路由需要身份验证。如果您没有通过身份验证,它应该会将您发送到登录页面,但在您登录后,它会将您返回到您之前请求的页面。我看了很多教程,也看了StackOverflow上的一些问题,但我认为问题是有些东西没有点击。我希望你们中的一个人能向我解释一下发生的事情背后的一些理论,也许能为我的问题指明正确的方向。我的代码在下面。我真正的问题是我并不真正理解next()范式。也许我做这一切都错了,思考的方式也错了。也许你也可以告诉我一些好主意。

编辑:

======

我找到了一个解决方案。稍后,我将为其他可能希望获得一些信息并解决此问题的人回答我的问题。

--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上的社区。你们在学习一项新技术的时候总是非常棒。

返回的next通常用于Connect中间件。您正在传递下一个要执行的函数的引用。中间件的作用就像过滤器,或链接列出的层(有点像,通过引用),您的函数在访问资源之前调用并遵循这些层,执行逻辑,然后决定退出/重定向或转到下一个中间件。中间件可能是身份验证,例如您正在使用的身份验证。尽管Passport是一个离散且编写良好的模块,但您在这里将其作为中间件来实现(这是正常的),这基本上是通过ensureAuthenticated功能实现的身份验证过滤器:您基本上只是在那里创建了自己的中间件(Achievement Unlocked)。您通常会在执行路由功能之前将所有中间件放在正确的位置。

据我所知,您所定义的-- DB Middleware并不是中间件。它看起来更像是一个模块,您正在尝试使用它来分离关注点(这很好)。我称之为model模块的开端。

看起来你的控制器可能会很快失控。我建议研究Routes

在Node.js、Express.js和Passport.js方面,我无论如何都不是专家,但我成功地将关注点和组织在一个部分工作的项目中的编码分离开来:https://github.com/Tzvayim/theArk/blob/master/app.js

最新更新