【问题标题】:PassportJS deserializeUser never calledPassportJS deserializeUser 从未调用过
【发布时间】:2012-07-01 22:18:01
【问题描述】:

我已经设置了 Passport 来验证存储在 mongodb 中的用户。似乎工作正常:身份验证成功/失败并设置会话变量。但是,让 Passport 检查会话失败。我添加到deserializeUser 回调中的console.log 语句似乎有些不对劲。我认为我的问题与 deserializeUser 从未被调用有关。谁能诊断出我的失误?

// Passport configuration
passport.serializeUser(function(user, cb){ cb(null, user.id) });
passport.deserializeUser(function(uid, cb){
  console.log("Trying to deserialize user: "+uid);
  User.findById(uid, function(err, user){
    cb(err, user);
  });
});
// auth strategy function
passport.use(new LocalStrategy({usernameField: 'email'},
  function(email, pass, done){
    User.findOne({email: email}, function (err, user) {
      if (err)
        return done(err);
      if (!user)
        return done(null, false, {message: "Couldn't find user"});
      var crypted = bcrypt.hashSync(pass, user.salt);
      if(user.hashpass != crypted)
        return done(null, false, {message: "Bad password"});
      return done(null, user);
    });
  }
));

passport.CreateSession =  function (req, res, next) {
  passport.authenticate('local', function(err, user, info){
    if(err || !user)
      return res.json({status: "Failure: "+err});
    req.logIn(user, function (err){
      if(err)
        return res.json({status: "Failure: "+err});
      return res.json({status: "Authenticated"});
    });
  })(req, res, next);
};

在 app.js 中添加以下内容:

app.post('/session', passport.CreateSession); // restify better
app.del('/session', passport.DestroySession);
app.get('/images', passport.CheckSession, routes.images);

【问题讨论】:

    标签: node.js session passport.js


    【解决方案1】:

    对于遇到此问题的其他人,请查看以下内容:

    app.use(session({ 
        secret: 'something', 
        cookie: { 
            secure: true
        }}));
    

    如果您将 cookie.secure 设置为 true 并且您没有使用 SSL(即 https 协议),则带有会话 ID 的 cookie 不会返回到浏览器,并且一切都会静默失败。删除这个标志为我解决了这个问题 - 我花了几个小时才意识到这一点!

    【讨论】:

    • 戴夫,这里的会话是“快速会话”吗?你能说清楚吗?
    • 这对我来说是个问题,我花了 2 个工作日才找到这个答案...谢谢!
    • 非常感谢。对我来说也是一样。正在调用序列化用户,但从不反序列化。浏览器中没有 cookie,req.session.passport 中也没有任何内容。翻转这面旗帜似乎有所帮助。即使它在本地运行,但在我在 Heroku 上运行并使用免费 SSL 的 prod 实例上,它不想设置安全 cookie。
    【解决方案2】:

    如果您在使用护照进行身份验证时使用authenticate 回调,则需要手动登录用户。它不会为你调用。

    passport.authenticate('local', function (err, user) {
        req.logIn(user, function (err) { // <-- Log user in
           return res.redirect('/'); 
        });
    })(req, res);
    

    【讨论】:

    • 来自护照的文档:Note: passport.authenticate() middleware invokes req.login() automatically. This function is primarily used when users sign up, during which req.login() can be invoked to automatically log in the newly registered user.
    • 您可能需要重新检查一下,如果您手动进行身份验证,它将不会被调用。
    • 它与 deserializeUser never 被调用 问题有什么关系?
    • console.log(err.message) after req.logIn(user, function (err) { show: Failed to serialize user into session ?
    • 在护照文档中关于authenticate中的自定义回调:The callback can use the arguments supplied to handle the authentication result as desired. Note that when using a custom callback, it becomes the application's responsibility to establish a session (by calling req.login()) and send a response.
    【解决方案3】:

    你有use()'d passport.session() 中间件吗?就像在这个例子中一样:

    https://github.com/jaredhanson/passport-local/blob/v1.0.0/examples/login/app.js#L91

    这就是恢复会话并调用 deserializeUser 的原因,所以听起来可能缺少它。

    【讨论】:

    • Jared - 感谢您的帮助。是的,我有 app.use(passport.session());在 app.js 中
    • 这是节点 0.8.0,express 2.5.10,以及最新的护照,顺便说一句。
    • 嗯,我假设您的会话设置正确并持续存在?如果是这样,我看不到任何明显的东西。这是我的建议: 1.尝试在节点0.6.x下运行,看看是否存在与0.8不兼容的地方。 2. 发布一个可运行的、复制粘贴的 gist,我会运行它,看看我能找到什么。
    • Jared - 我正在使用 express.cookieParser()、express.session({secret: 'somethingsecret'}) 和 passport.session()……还有什么我想念的吗?使用节点 0.6.0 尝试过,但没有任何乐趣。如果该会话设置看起来正确并且您没有看到任何其他内容,我将在今晚晚些时候发布一个要点。非常感谢您的帮助 - 节点社区确实受益于像您这样的人帮助用户。
    • 另外,passport.session() 应该在app.use(session… 的下方/之后
    【解决方案4】:

    好的,这花了我将近 3 天的时间来解决,这似乎是一个简单的修复,至少在我的情况下。我必须放置:

    app.use(require('cookie-parser'));
    

    app.use(require('express-session')({
        secret: 'keyboard cat',
        resave: false,
        saveUninitialized: false
    }));
    

    打电话之前:

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

    注意:这些 sn-ps 不是我的实际代码,我取自 GitHub,但这就是它的要点。

    【讨论】:

      【解决方案5】:

      就我而言,这是因为我有这个代码:

      app.get("/auth/google/callback", 
          passport.authenticate("google", { 
              failureRedirect: "/admin/login/?error",
          }),
          (req, res) => {
              return res.redirect("/admin/");
          },
      );
      

      显然在这种情况下 req.login() 不会被调用(它调用反序列化)。我把它改成了这个,它起作用了:

      app.get("/auth/google/callback", 
          passport.authenticate("google", { 
              successRedirect: "/admin/", 
              failureRedirect: "/admin/login/?error",
          })
      );
      

      【讨论】:

        【解决方案6】:

        今天我遇到了同样的问题,就我而言,原因是客户端如何进行 API 调用。以下方法帮助我克服了这个问题:

        const doFetch(url, method = 'GET', body) {
          const headers = new Headers();
          headers.append('Content-Type', 'application/json');
          headers.append('Accept', 'application/json');
          headers.append('Cache', 'no-cache');
          const params = { 
            method, headers, 
            credentials: 'include' // The cookie must be sent!
          }
          if(body) {
            params.body = body;
          }
          return fetch(url, params);
        }
        

        此后,deserializeUser 开始被正常调用。

        【讨论】:

          【解决方案7】:

          我整天都在同一个问题作斗争。我设置了一个自定义回调来进行授权(例如在http://passportjs.org/guide/authenticate/ 的底部)。看起来 Passport 在所有请求对象到达其他中间件之前就对其进行了预处理(基于我编写的一些日志记录语句)。作为该预处理的一部分,它将反序列化的用户信息放入 request.user 对象中。不幸的是,passport.authenticate ('local', callback) 的默认行为似乎是忽略任何会话或 cookie 数据,而是假设用户名和密码是在请求对象中发送的。为了解决这个问题,我首先检查了 request.user 对象,如果它存在,则意味着 Passport 已经完成了它的预处理,然后我可以直接调用 login。这是我的授权函数,我用它代替了 passport.authenticate('local'):

          function doAuth(request, response, next)
          { 
          
          if (request.user) {
              request.logIn(request.user, function (err) {
                  if (err) {
                      console.log(err);
                      response.status(500).json({message:
                              "Login failed. Auth worked. Nonsense"});
                      return;
                  }
                  console.log("doAuth: Everything worked.");
                  next();
              });
              return;
          }
          
          passport.authenticate('local', function(err, user, info) {
              if (err) {
                  response.status(500).json({message: "Boo Passport!"});
                  return; //go no further
                  //until I figure out what errors can get thrown
              }
              if (user === false) {
                  console.log("Authentication failed. Here is my error:");
                  console.log(err);
                  console.log("Here is my info:");
                  console.log(info);
                  response.status(500).json({message: "Authentication failed."});
                  return;
              }
              request.logIn(user, function(err) {
                  if (err) {
                  console.log("Login failed. This is the error message:");
                  console.log(err);
                  response.status(500).json({message:"Login failed."});
                      return;
                  }
                  console.log("doAuth: Everything worked. I don't believe it.");
          
                  next();
              });
          })(request, response, next);
          
           }
          

          【讨论】:

          • 您的解释对我帮助很大,谢谢!我没有应用您的解决方案,但您指出了问题:D
          【解决方案8】:

          在我的情况下,我已经放置了

          app.use(cookieSession({
            maxAge : 60*60*1000,
            keys : [key.cookieSession.key1]
          }));
          

          上面

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

          它成功了。

          【讨论】:

            【解决方案9】:

            我用网络安全打开谷歌浏览器或打开隐身模式,它对我有用

            web-security for linux /usr/bin/google-chrome-stable
            --disable-web-security --user-data-dir=/home/jossnaz/.config/google-chrome/
            

            【讨论】:

              【解决方案10】:

              Heroku 中,所有请求都以纯 http 形式进入应用程序,但带有 X-Forwarded-Proto 标头以了解原始请求是 http 还是 https。

              这会导致 express 看到非 ssl 流量,因此它在 Heroku 上运行时拒绝设置安全 cookie。您必须通过设置“信任代理”告诉 express 信任该标头中的信息。

              app.set('trust proxy', 1);
              

              就在之前

              app.use(session...
              

              如果您在 Heroku 上遇到此问题,可能对您有用。如果您的 cookie/会话搞砸了,那么这可能就是不调用反序列化的原因。

              【讨论】:

                【解决方案11】:

                确保代码行app.use(express.static(path.join(__dirname, 'public'))); 保持在app.use(require('express-session') 下方

                【讨论】:

                • 为什么?此顺序对问题无关紧要 - deserializeUser 也不会被调用。此外,您还可以对每个资产请求进行数据库查询。您确定需要为每个styles.css 查询会话吗?
                【解决方案12】:
                passport.serializeUser(
                    function(user, done){
                        done(null, user.id);
                });
                
                passport.deserializeUser(
                    function(id, done){
                        User.findById(id, function(err, user){
                            if(err){
                                done(err);
                            }
                            done(null, user);
                        });
                });
                
                **> try this one**
                

                【讨论】:

                  猜你喜欢
                  • 2016-03-24
                  • 1970-01-01
                  • 2015-05-17
                  • 1970-01-01
                  • 2014-11-24
                  • 1970-01-01
                  • 2023-03-19
                  • 2017-11-06
                  • 2015-04-01
                  相关资源
                  最近更新 更多