护照会话显示未定义的req.user

3

当我登录时,req.user会正常显示,但是在导航到/test后,req.user变为undefined

这是为什么呢?

server.js

var express    = require('express');        // call express
var app        = express();                 // define our app using express
var bodyParser = require('body-parser');
var mongoose = require('mongoose');
var session      = require('express-session');
var router = express.Router();
var Account = require('src/app/models/Users.js');
var Core = require('/src/app/gamemodels/core');
// Init passport authentication
var passport = require('passport');
var Strategy = require('passport-local').Strategy;
require('/src/config/passport')(passport);
var cookieParser = require('cookie-parser')



// required for passport session

app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
mongoose.connect('DB');
app.use(cookieParser()) // required before session.

app.use(session({ secret: 'xxxx' }));
app.use(passport.initialize());
app.use(passport.session());






var port = process.env.PORT || 3000;        // set our port


// test route to make sure everything is working (accessed at GET http://localhost:8080/api)
router.get('/', function(req, res) {
    res.json({ text: 'hooray! welcome to our api!' });
});


router.get('/test', function(req,res) {
    console.log(req);
    console.log(req.user);
    res.json(req.user);
});


router.post('/signup', passport.authenticate('local-signup', {
    successRedirect : '/profile', // redirect to the secure profile section
    failureRedirect : '/signup', // redirect back to the signup page if there is an error
}));

router.post('/login', passport.authenticate('local-login'), function(req, res) {

    console.log("executed login!");
    console.log(req.user);
    req.session.user = req.user;

});


});
*/



// more routes for our API will happen here

// REGISTER OUR ROUTES -------------------------------
// all of our routes will be prefixed with /api
app.use('/api', router);

// START THE SERVER
// =============================================================================
app.listen(port);
console.log('Magic happens on port ' + port);

Passport JS:

// config/passport.js

// load all the things we need
var LocalStrategy   = require('passport-local').Strategy;

// load up the user model
var Account = require('src/app/models/Users.js');

// expose this function to our app using module.exports
module.exports = function(passport) {

    passport.serializeUser(function(user, done) {
        done(null, user);
    });

    // used to deserialize the user
    passport.deserializeUser(function(id, done) {
        Account.findById(id, function(err, user) {
            done(err, user);
        });
    });

    passport.use('local-login', new LocalStrategy({
            // by default, local strategy uses username and password, we will override with email
            usernameField : 'username',
            passwordField : 'password',
            passReqToCallback : true // allows us to pass back the entire request to the callback
        },
        function(req, username, password, done) { // callback with email and password from our form
            console.log("doing local login");
            // find a user whose email is the same as the forms email
            // we are checking to see if the user trying to login already exists
            Account.findOne({ 'username' :  username }, function(err, user) {
                var thisuser = user;
                console.log("query account is done");
                // if there are any errors, return the error before anything else
                if (err) {
                    console.log("error occured");
                    return done(err);
                }

                console.log("if user exist check");


                // if no user is found, return the message
                if (!user)
                    return done(null, false,'No user found.'); // req.flash is the way to set flashdata using connect-flash


                console.log("checking password");
                // if the user is found but the password is wrong
                if (!user.validPassword(password)) {
                    console.log("password is not valid");
                    return done(null, false, 'Oops! Wrong password.'); // create the loginMessage and save it to session as flashdata

                }
                console.log("all good! logging in!");


                req.login(thisuser, function(error) {
                    if (error) return next(error);
                    console.log("Request Login supossedly successful.");
                });

                // all is well, return successful user
                return done(null, thisuser);
            });

        }));

    passport.use('local-signup', new LocalStrategy({
            // by default, local strategy uses username and password, we will override with email
            usernameField : 'email',
            passwordField : 'password',
            passReqToCallback : true // allows us to pass back the entire request to the callback
        },
        function(req, username, password, done) {
            process.nextTick(function() {
                    console.log("doing local signup");
                // find a user whose email is the same as the forms email
                // we are checking to see if the user trying to login already exists
                Account.findOne({ 'username' :  username }, function(err, user) {
                    // if there are any errors, return the error
                    if (err)
                        return done(err);

                    // check to see if theres already a user with that email
                    if (user) {
                        return done(null, false, 'That username is already taken.');
                    } else {

                        var newUser            = new Account();

                        // set the user's local credentials
                        newUser.username    = username;
                        newUser.password = newUser.encryptPassword(password);

                        // save the user
                        newUser.save(function(err) {
                            if (err)
                                throw err;
                            return done(null, newUser);
                        });
                    }

                });

            });

        }));

};

编辑1:

将passport.js的序列化函数和反序列化函数更改为以下内容:

passport.serializeUser(function(user, done) {
    done(null, user.username);
});

// used to deserialize the user
passport.deserializeUser(function(username, done) {
    Account.findOne({'username': username}, function(err, user) {
        done(err, user);
    });
});

仍然没有任何区别。 'Undefined' 仍然出现。

编辑2:

用户序列化的值:

{ _id: 5909a6c0c5a41d13340ecf94,
  password: '$2a$10$tuca/t4HJex8Ucx878ReOesICV6oJoS3AgYc.LxQqCwKSV8I3PenC',
  username: 'admin',
  __v: 0,
  inFamily: false,
  bank: 500,
  cash: 2500,
  xp: 0,
  rank: 1,
  bullets: 0,
  location: 1,
  permission: 0,
  health: 100 }

编辑3:

将登录功能更改为:

router.post('/login', passport.authenticate('local-login'), function(req, res) {

    console.log("executed login!");
    console.log(req.user);
    req.session.user = req.user;
    req.logIn(req.user, function (err) {
        if (err) {
            return next(err);
        }

    });

});

服务器日志响应:

doing local login
query account is done
if user exist check
checking password
all good! logging in!
serializing!
Request Login supossedly successful.
serializing!
executed login!
{ _id: 5909a6c0c5a41d13340ecf94,
  password: '$2a$10$tuca/t4HJex8Ucx878ReOesICV6oJoS3AgYc.LxQqCwKSV8I3PenC',
  username: 'admin',
  __v: 0,
  inFamily: false,
  bank: 500,
  cash: 2500,
  xp: 0,
  rank: 1,
  bullets: 0,
  location: 1,
  permission: 0,
  health: 100 }
serializing!

仍然没有反序列化日志的迹象。

2个回答

3
在passport对象上定义方法和中间件时,顺序很重要。您的代码相当纠缠。在这里进行一些解耦会有很大的帮助。
  1. 将所有策略逻辑从server.js和passport.js中移出,并将其放入自己的文件集中。此外,您不需要在服务器文件中包含基础策略。

  2. 在单独的文件中定义一个express路由器,并在server.js中挂载路由。

  3. passport.initialize()和passport.session()中间件需要在定义serialize和deserialize之前附加到您的express应用程序实例之前

  4. 没有必要设置req.session.user,这会破坏仅在会话中存储用户ID的目的。在每个对express的请求中,一旦通过读取req.session.passport.user中的id反序列化用户,您就可以将整个用户帐户文档加载到req.user中,并直接从req.user访问所有用户数据。

  5. 如果使用预打包的护照策略构造函数调用了done(),则无需在任何地方调用req.login。

server.js

//express, body parser, express session, etc

const app = express();
const passport = require('passport');
const user = require('./passport-serialize');
const routes = require('./routes');

//lots of middleware

//session middleware

app.use(passport.initialize());
app.use(passport.session());

passport.serializeUser(user.serialize);

passport.deserializeUser(user.deserialize);

app.use('/api', routes);

//actual server, more stuff

passport-serialize.js

//include Account model

const user = {
  serialize: (user, done) => {
    done(null, user.username)
  },
  deserialize: (username, done) => {
    Account.findOne({'username': username}, function(err, user) {
    done(err, user);
  }
}

module.exports = user;

routes.js

const express = require('express');

const router = new express.Router();

const passport = require('./strategies');

//many routes

router.post('/login', passport.authenticate('local-login'), function(req, res) {
  console.log("executed login!");
  console.log(req.user);
});

router.get('/test', function(req, res) {
  console.log(req.user);
  res.json(req.user);
});



module.exports = router;

strategies.js

const passport = require('passport');
const LocalStrategy = require('whatever the package is');
//Account model

passport.use('local-login', new LocalStrategy({
  // by default, local strategy uses username and password, we will override with email
  usernameField : 'username',
  passwordField : 'password',
  passReqToCallback : true // allows us to pass back the entire request to the callback
},  function(req, username, password, done) { // callback with email and password from our form
  console.log("doing local login");
  // find a user whose email is the same as the forms email
  // we are checking to see if the user trying to login already exists
  Account.findOne({ 'username' :  username }, function(err, user) {
    var thisuser = user;
    console.log("query account is done");
    // if there are any errors, return the error before anything else
    if (err) {
      console.log("error occured");
      return done(err);
    }
    console.log("if user exist check");

    // if no user is found, return the message
    if (!user)
      return done(null, false,'No user found.'); 
      // req.flash is the way to set flashdata using connect-flash
      console.log("checking password");
      // if the user is found but the password is wrong
    } else if (!user.validPassword(password)) {
      console.log("password is not valid");
      return done(null, false, 'Oops! Wrong password.'); 
      // create the loginMessage and save it to session as flashdata
    }
    console.log("all good! logging in!");
    // all is well, return successful user
    return done(null, thisuser);
  });
}));
        
 module.exports = passport;


非常喜欢这个答案,正在尝试将我的大量代码重构为类似的更整洁的文件。然而在测试过程中,我注意到 passport-serialize.js 缺少与反序列化相关的 ) 和 }。花了我一些时间才发现这两个问题,因此可能值得加上注释。 - Vka
我相信这是第二段代码片段。 - Sarah Riehl

3
原因在于您缺少反序列化部分。
    /**
     * Each subsequent request will contain a  unique 
     * cookie that identifies the session. In order to support login sessions, 
     * Passport will serialize and deserialize user instances to and from the session.
     */
    passport.serializeUser(function (user, done) {
        done(null, user.username);
    });

    passport.deserializeUser(function (username, done) {
        /**
         * Necessary to populate the express request object with
         * the 'user' key
         * Requires(*):
         *  - session support with express
         *  - call to logIn from passport.auth)enticate if using authenticate
         *   callback.
         */
        // TODO: Verify if username exists
        done(null, username);
    });

当用户通过身份验证或req.isAuthenticated()返回true时,反序列化中间件函数将被调用,并将更新请求对象中的username或在您的情况下是req.user

参考:

由于您正在使用自定义回调函数来处理成功或失败,因此需要应用程序负责通过调用req.logIn来建立一个会话。因此,在用户经过身份验证后,请添加:

req.logIn(user, function (err) {
    if (err) { return next(err); }
    return { // Do a redirect perhaps? }
});

请参考我给你的参考链接中的 自定义回调函数 部分。

serialize 中间件中的 user 的值是什么? - Suhail Gupta
更新了我的回答。 - Suhail Gupta
我一开始尝试了那个,但仍然不起作用。 - maria
很抱歉地说,根据未定义或无法序列化的情况下,没有任何更改。 - maria
我在中间件本身不使用自定义回调函数。 - maria
显示剩余12条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接