Вопрос

I'm working on developing a node.js (using node.js v0.10.26) express web application using Google's oauth 2.0 with passport.js. Up to now it's worked fine, as the route definitions were contained within the app.js file. However, now that I'm breaking up the route logic into separate modules, I'm running into problems. My file structure is broken up like this:

authentication
├── cert.pem
└── key.pem
bin
└── www
data
└── (mongo database files)
node_modules
└── (node module files for: body-parser, cookie-parser, 
    debug, express, express-session, jade, method-override, 
    mongodb, mongoose, morgan, passport, passport-google, static-favicon)
routes
├── account.js
├── index.js
└── login.js
views
├── account.jade
├── index.jade
├── layout.jade
└── login.jade
app.js
oauth.js
package.json

The .pem files are for the ssl key and certificate. www is a script which establishes an https server:

var debug = require('debug')('kaiwaquiz');
var fs = require('fs');
var http = require('http');
var https = require('https');
var app = require('../app');
var options = {
    key: fs.readFileSync('./authentication/key.pem'),
    cert: fs.readFileSync('./authentication/cert.pem')
};
var port = process.env.PORT || 3000;
var server = https.createServer(options, app).listen(port, function(){ 
    debug('Express server listening on port ' + server.address().port);
});

It calls uses app.js (note the comment above the /login route):

//Express Dependencies
var express = require('express');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var logger = require('morgan');
var session = require('express-session');
var methodOverride = require('method-override');
var favIcon = require('static-favicon');

//Passport Dependencies
var config = require('./oauth.js');
var passport = require('passport');
var GoogleStrategy= require('passport-google').Strategy;

//Mongo Dependencies
var mongodb = require('mongodb');
var mongoose = require('mongoose');

//Server Variables
var app = express();
var indexRoutes = require('./routes/index');
var loginRoutes = require('./routes/login');
var accountRoutes = require('./routes/account');

//Serialize and Deserialize
passport.serializeUser(function(user, done) {
    done(null, user);
});
passport.deserializeUser(function(obj, done){
    done(null, obj);
});

//Passport Configuration
passport.use(new GoogleStrategy({
        clientID: config.google.clientID,
        clientSecret: config.google.clientSecret,
        returnURL: config.google.returnURL,
        realm: config.google.realm
    },
    function(accessToken, refreshToken, profile, done){
        process.nextTick(function(){
            app.locals.currentUserName = refreshToken.displayName;
            return done(null, profile);
        });
    }
));

//Configure View Engine
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');

//Process Static Content
app.use(favIcon());
app.use(express.static(__dirname + '/public'));

//Process Dynamic Content
app.use(cookieParser());
app.use(bodyParser());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded());
app.use(methodOverride());
app.use(session({secret: 'its_a_secret'}));
app.use(passport.initialize());
app.use(passport.session());

//Log results
app.use(logger('dev'));

function ensureAuthenticated(req, res, next) {
    if(req.isAuthenticated()) {return next();}
    res.redirect('/login');
}

//Application Routes
///THE FOLLOWING WORKS FINE///
app.get('/', indexRoutes);
///THE FOLLOWING /LOGIN ROUTE FAILS UNLESS THE loginRoutes MODULE IS REPLACED BY function(req, res){ res.render('login'); }///
app.get('/login', loginRoutes);
app.get('/account', ensureAuthenticated, accountRoutes);

app.get('/auth/google', passport.authenticate('google'), function(req, res){});
app.get('/auth/google/callback', passport.authenticate('google', {failureRedirect: '/'}),
    function(req, res){
        res.redirect('/account');
    }
);
app.get('/logout', function(req, res){
    req.logout();
    res.redirect('/');
});

module.exports = app;

The index route works fine, and uses index.js:

var express = require('express');
var router = express.Router();

/* GET home page. */
router.get('/', function(req, res) {
  res.render('index');
});

module.exports = router;

The login route fails, even though login.js employs the same format:

var express = require('express');
var router = express.Router();

/* GET home page. */
router.get('/', function(req, res) {
  res.render('login');
});

module.exports = router;

It still fails, even if I use index.js, and only works if I put the res.render() function directly in the code like this:

app.get('/login', function(req, res){ 
    res.render('login'); 
});

The oauth.js file just contains the client information for connecting using google.com Does anyone have any ideas as to why this problem is occuring?

Edit: If I change the /login route, the /account route breaks in the same way that /login did. So, this app.js works fine:

//Express Dependencies
var express = require('express');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var logger = require('morgan');
var session = require('express-session');
var methodOverride = require('method-override');
var favIcon = require('static-favicon');

//Passport Dependencies
var config = require('./oauth.js');
var passport = require('passport');
var GoogleStrategy= require('passport-google').Strategy;

//Mongo Dependencies
var mongodb = require('mongodb');
var mongoose = require('mongoose');

//Server Variables
var app = express();
var indexRoutes = require('./routes/index');
var loginRoutes = require('./routes/login');
var accountRoutes = require('./routes/account');

//Serialize and Deserialize
passport.serializeUser(function(user, done) {
    done(null, user);
});
passport.deserializeUser(function(obj, done){
    done(null, obj);
});

//Passport Configuration
passport.use(new GoogleStrategy({
        clientID: config.google.clientID,
        clientSecret: config.google.clientSecret,
        returnURL: config.google.returnURL,
        realm: config.google.realm
    },
    function(accessToken, refreshToken, profile, done){
        process.nextTick(function(){
            app.locals.currentUserName = refreshToken.displayName;
            return done(null, profile);
        });
    }
));

//Configure View Engine
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');

//Return Static Content
app.use(favIcon());
app.use(express.static(__dirname + '/public'));

//Return Dynamic Content
app.use(cookieParser());
app.use(bodyParser());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded());
app.use(methodOverride());
app.use(session({secret: 'its_a_secret'}));
app.use(passport.initialize());
app.use(passport.session());

//Log results
app.use(logger('dev'));

function ensureAuthenticated(req, res, next) {
    if(req.isAuthenticated()) {return next();}
    res.redirect('/login');
}

//Application Routes
app.get('/login', function(req, res){
    res.render('login');
});
app.get('/account', ensureAuthenticated, function(req, res){
    res.render('account', {user: req.app.locals.currentUserName});
});
app.get('/', function(req, res){
    res.render('index');
});

app.get('/auth/google', passport.authenticate('google'), function(req, res){});
app.get('/auth/google/callback', passport.authenticate('google', {failureRedirect: '/'}),
    function(req, res){
        res.redirect('/account');
    }
);
app.get('/logout', function(req, res){
    req.logout();
    res.redirect('/');
});

module.exports = app;
Это было полезно?

Решение 2

try the following as login.js:

var express = require('express');
var router = express.Router();

/* GET login page. */
router.get('/login', function(req, res) {
  res.render('login');
});

module.exports = router;

Другие советы

According to the Router documentation, I think you need to do

app.use('/login', loginRoutes);

instead of

app.get('/login', loginRoutes);

Same goes for your index and other routes that are using express.Router().

The documentation says:

// will handle any request that ends in /events
// depends on where the router is "use()'d"
router.get('/events', function(req, res, next) {
  // ..
});

Through some trial and error, I've been able to determine that external routing modules must be use()'d, instead of get()'d, like mscdex indicated. However, the end routes must use an http verb like get(), post(), etc... The /account route, which currently uses a get(), contains two methods, the ensureAuthenticated(), and inline rendering method. This is because the http verb methods can contain more than one method to be executed, as opposed to the use(). For the future, it seems better to do the authentication within the routing modules themselves, as the method to do so is added to the request variable. Thanks for the assistance!

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top