2012-12-18 10 views
8

Walczę z niektórymi teoriami i konwencjami za niektórymi frameworkami Node.js. Jestem nowy w Node.js. Próbuję skonfigurować scenariusz, w którym mam strukturę MVC, w której definiuję zestaw kontrolerów, które wykonują podstawowe funkcje odpoczynku, a niektóre z moich tras kontrolera wymagają uwierzytelnienia. Jeśli nie jesteś uwierzytelniony, powinien wysłać cię na stronę logowania, ale po zalogowaniu się, odsyła cię z powrotem na stronę, o którą wcześniej prosiłeś. Przyjrzałem się kilku tutorialom i przyjrzałem się niektórym pytaniom na temat StackOverflow, ale myślę, że problem polega na tym, że coś po prostu nie klika. Mam nadzieję, że ktoś z was może mi trochę wyjaśnić teorię stojącą za tym, co się dzieje, i być może wskazać mi właściwy kierunek mojego problemu. Mój kod znajduje się poniżej. Moim prawdziwym problemem jest to, że tak naprawdę nie rozumiem tego paradygmatu next(). Może robię to wszystko źle i myślę o tym w niewłaściwy sposób. Może wpuścisz mnie także w dobre pomysły.Teoria Node.js - Node.js, Express.js, Passport.js

Edit:

======

znalazłem rozwiązanie. Odpowiem później na moje pytanie dla każdego, kto może chcieć uzyskać pewne informacje i rozwiązać ten problem.

- 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); 

- Ludzie kontroler

/** 
* 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(); 

- Praca Kontroler

/** 
* 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 Middleware

/** 
* 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(); 

Dziękujemy wam z góry. Uwielbiam społeczność na StackOverflow. Jesteście zawsze niesamowici, gdy uczysz się nowej technologii.

+2

Tylko komentarz, jeśli ekspres może być skonfigurowany do wyświetlania plików statycznych nie oznacza, że ​​jest to najlepsze rozwiązanie, zwykle używasz nginx dla ten cel. –

+0

Zrozumiano. To tylko konfiguracja wstępnego przejścia. Chciałbym później przekonwertować serwer HTTP na zawartość statyczną. –

+0

TJ Holowaychuk ma [przykład] (https://github.com/visionmedia/express/tree/master/examples/mvc) implementacji MVC za pomocą ekspresu – verybadalloc

Odpowiedz

1

Powracanie next są zwykle dla oprogramowania pośredniego Connect. Przekazujesz referencję następnej funkcji do wykonania. Oprogramowanie pośredniczące zachowuje się jak filtry lub połączone warstwy (rodzaj, przez odniesienie), które twoja funkcja dzwoni i przechodzi przez nią, zanim dostanie się do twoich zasobów, logika, a następnie decyduje się wyjść/przekierować lub przejść do następnego oprogramowania pośredniczącego. Oprogramowanie pośredniczące może być uwierzytelnianie, takie jak używasz. Chociaż Passport jest dyskretnym i dobrze napisanym modułem, implementujesz go jako oprogramowanie pośredniczące (co jest normalne), które jest w zasadzie filtrem uwierzytelniającym poprzez twoją funkcję ensureAuthenticated: w zasadzie właśnie stworzyłeś tam własne oprogramowanie pośrednie (Achievement Unlocked) . Zwykle umieszczasz wszystkie swoje Middleware tuż przed wykonaniem funkcji Routingu.

To, co określasz jako -- DB Middleware, nie jest oprogramowaniem pośredniczącym, z tego, co mogę powiedzieć. Wygląda bardziej jak moduł, z którym próbujesz osobne problemy (co jest dobre). Nazwałbym to początkami twojego modułu model.

Wygląda na to, że kontrolerzy mogą szybko wymknąć się spod kontroli. Proponuję badanie Routes.

Nie jestem ekspertem w żaden sposób w odniesieniu do Node.js, Express.js i Passport.js, ale udało mi się oddzielić problemy i kodowanie zorganizowane w częściowo pracujący projekt: https://github.com/Tzvayim/theArk/blob/master/app.js

Powiązane problemy