8

我正在为一些 Node.js 框架背后的一些理论和惯例而苦苦挣扎。我是 Node.js 的新手。我正在尝试设置一个场景,其中我有一个 MVC 框架,我在其中定义了一组执行基本休息功能的控制器,并且我的一些控制器路由需要身份验证。如果您未通过身份验证,它应该将您发送到登录页面,但在您登录后,它会将您发送回您之前请求的页面。我查看了一堆教程,也查看了 StackOverflow 上的一些问题,但我认为问题在于某些内容没有点击。我希望你们中的一个人可以向我解释一下正在发生的事情背后的一些理论,也许能为我的问题指出正确的方向。我的代码如下。我真正的问题是我不 t 真正理解这个 next() 范式。也许我什至做错了这一切,并以错误的方式思考它。也许你也可以让我谈谈一些好主意。

编辑:

======

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

-- 服务器.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
 */

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 上的社区。你们在学习新技术时总是那么棒。

4

1 回答 1

1

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

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

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

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

于 2013-07-31T23:47:12.593 回答