【问题标题】:Session issues with Passport.js and RestifyPassport.js 和 Restify 的会话问题
【发布时间】:2015-04-20 06:38:28
【问题描述】:

我正在尝试开发一个简单的概念证明,将 Passport 的 Google 身份验证策略与 Restify 和 Bookshelf.js 结合使用。我希望这个简单的应用程序能够让我解析 /sessions/google 路由(它调用 Google 身份验证)并在成功身份验证后重定向到 /sessions/googleReturn。对于这个简单的概念证明,请假设与 User 模型对应的表包含正在验证的用户的记录。

下面是我目前正在试验的代码。目前,此代码在验证后会导致无休止的重定向循环。如果我删除 /sessions/googleReturn 路由中的 'passport.authenticate('google', { failureRedirect: '/' })' 行,则 /sessions/googleReturn 会解析但 req.user 返回一个空对象。我猜我没有初始化会话或将会话正确绑定到护照。护照方法中的 console.log 输出似乎被禁止,这使得调试变得困难。如果我用 express/express-session 替换 Restify/client-sessions,我的概念证明就有效。我究竟做错了什么?提前致谢。

var restify = require('restify');
var sessions = require('client-sessions');
var passport = require('passport');
var GoogleStrategy = require('passport-google').Strategy;
var User = require('./models/user'); // Bookshelf model

var server = restify.createServer({ name: 'test-server' });

server
  .use(sessions({
    cookieName: 'user',
    secret: 'topsecret',
    duration: 365 * 24 * 60 * 60 * 1000}))
  .use(passport.initialize())
  .use(passport.session());

passport.serializeUser(function(user, done) {
  console.log('serialize user:', user);
  done(null, user.id);
});

passport.deserializeUser(function(id, done) {
  console.log('deserialize user:', id);
  new User({ id: id }).fetch({require: true}).then(function(user) {
    done(null, user);
  }).catch(function(err) {
    done(err, null);
  });
});

passport.use(
  new GoogleStrategy({
    returnURL: 'http://localhost:3000/sessions/googleReturn',
    realm: 'http://localhost:3000'
  },
  function(identifier, profile, done) {
    console.log('Hello from the verify callback', identifier, profile);
    new User({ email: profile.emails[0].value }).fetch({require: true}).then(function(user) {
      done(null, user);
    }).catch(function(err) {
      done(err, null);
    });
  }
));

server.listen(3000, function () {
  console.log('%s listening at %s', server.name, server.url);
});

server.get('/', function(req, res, next) {
  res.send(200, 'Hello from root route.');
  return next();
});

server.get(
  '/sessions/google',
  passport.authenticate('google')
);

server.get(
  '/sessions/googleReturn',
  passport.authenticate('google', { failureRedirect: '/' }),
  function(req, res, next) {
    console.log('Session user data?', req.user);
    res.send(200, 'Hello from Google auth return route.');
    return next();
  }
);

【问题讨论】:

    标签: node.js session authentication passport.js restify


    【解决方案1】:

    如果您看到来自 google auth 的响应,它会说 302 临时移动。 此外,google openid 已被弃用,并被 google-plus 登录所取代。

    Google OpenID:https://developers.google.com/accounts/docs/OpenID

    如果你想使用,有一个用于 google-plus 登录的 npm 模块。

    npm install passport-google-plus https://www.npmjs.com/package/passport-google-plus

    【讨论】:

    • 有趣的是,我对 Facebook/Twitter/Github 策略也有同样的问题。不过,感谢您对 Google Plus 策略模块的提醒。
    • 你能试试这些改变吗....server.get( '/sessions/googleReturn', function(req, res, next) { console.log('Session user data?', res); res.send(200, 'Hello from Google auth return route.'); return next(); } );
    • 我尝试了您的代码,它通过删除 "/sessions/googleReturn" 路由中的 passport.authenticate 来工作,并且响应在响应 res 中包含 openid 用户信息。
    • 那么 res 下的什么对象包含用户模型或 Google 个人资料对象?我在“res”下看到了几个包含引荐来源信息的对象,但这似乎不是我想要使用的。护照文档建议您将用户模型序列化到会话;会话设置为将“用户”对象绑定到“请求”对象。
    • 好的,我发现这个问题与你的类似。 stackoverflow.com/questions/20631996/passportjs-redirect-loop
    【解决方案2】:

    当我遇到这个问题时,我发现我需要确保 restify 已准备好解析查询参数。我的重定向循环消失了。

    server = restify.createServer({ name: 'test-server' });
    server.use(restify.queryParser());
    

    【讨论】:

      【解决方案3】:

      如果您使用的是restify,它的重定向功能会略有不同。您可以简单地添加一个覆盖,例如:

      function patchRedir(){
          return function( req, res, next ){
              res.redirect = function( url ){
                  res.header( 'Location', url )
                  res.send( 302 )
              }
              return next()
          }
      }
      server.get('/auth/facebook/callback', patchRedir(), passport.authenticate('facebook', { failureRedirect: '/login' }), ( req, res, next ) => {
          // Successful
          res.send( 200 )
      })
      

      【讨论】:

        【解决方案4】:

        client-sessions 包在req 中设置一个会话对象,其名称与会话cookie 名称相同。它默认为session,这意味着req.session 对象可用。我发现passport.js(实际上是passport-oauth2)需要这样的对象才能将用户保存到会话中。因此,通过更改client-sessions 配置中的cookieName,您可以使其对req 中的会话对象使用不同的键!

        GoogleStrategy 使用passport-oauth2 作为它的基础,您可以检查确实需要req.session 的来源: https://github.com/jaredhanson/passport-oauth2/blob/master/lib/state/session.js

        我发现了两种解决方案:

        1. 要么使用session cookie 名称
        2. 为您重新设置服务器制作一个小型的“通用处理程序”,如果您设置会话但您设置护照之前放置:

          server.use((req, res, next) => {
              req.session = req.your_cookie_name;
              return next();
          });
          

        【讨论】:

          猜你喜欢
          • 2014-03-21
          • 2023-04-07
          • 2013-02-12
          • 2023-04-08
          • 1970-01-01
          • 2019-06-09
          • 1970-01-01
          • 2013-08-29
          • 2018-07-21
          相关资源
          最近更新 更多