使用 PassportJS 和 Connect for NodeJS 来验证 Facebook 用户

Posted

技术标签:

【中文标题】使用 PassportJS 和 Connect for NodeJS 来验证 Facebook 用户【英文标题】:Using PassportJS with Connect for NodeJS to authenticate Facebook Users 【发布时间】:2012-06-15 21:43:50 【问题描述】:

我正在尝试使用 connect 将护照集成到我的 nodejs 服务器中,但似乎无法正确完成。所有指南/示例都使用 expressJS,所以我尽力重新格式化代码以使用我的代码,但我似乎无法让它工作。相关部分写在下面。有人对可能出现的问题有什么建议吗? passport.authenticate() 似乎从未被调用(至少 facebook 身份验证回调中的 console.log 消息从不打印)。我目前没有将任何内容保存到数据库中,所以希望这个问题应该是我刚刚错过的非常简单的事情。

唯一想到的是我对 facebook 的潜在回调,它是一个 localhost url(因为我仍在本地开发它)。我能够使用everyauth(来自纯粹的本地实例)很好地使用facebook进行身份验证,但切换到passportJS,因为我在那里遇到了passportJS似乎解决的不同问题。

passport = require('passport');
  fpass = require('passport-facebook').Strategy;

passport.serializeUser(function(user,done)
    done(null, user);
);
passport.deserializeUser(function(obj,done)
    done(null,obj);
);

passport.use(new fpass(
        clientID:'facebook app id',
        clientSecret:'facebook app secret',
        callbackURL:'http://localhost:3000/auth/facebook/callback'
    ,
    function(accessToken, refreshToken, fbUserData, done)
        console.log('got here');
        return done(null,fbUserData);
    
));



    function checkLoggedIn(req, res, next)
        console.log("req.user: " + req.user);
        if(req.user)
            next();
        else
            console.log('\nNot LOGGED IN\n');
            if(req.socket.remoteAddress || req.socket.socket.remoteAddress == '127.0.0.1')
                var folder,contentType;
                console.log('req url = '+req.url);
                if(req.url == '/')
                    folder = __dirname + '/landingPage.html';
                    contentType = 'text/html';
                
                else if(req.url == '/auth/facebook')
                    passport.authenticate('facebook');
                    return;
                
                else if(req.url == '/auth/facebook/callback')
                    passport.authenticate('facebook', failureRedirect: '/failbook', successRedirect:'/');
                    return;
                
                if(folder)
                    console.log('got to folder part\n\n');
                    fs.readFile(folder, function(error, content)
                      if(error)
                        res.writeHead(500);
                        res.end();
                      
                      else
                        res.writeHead(200, 'Content-Type': contentType);
                        res.end(content);
                      
                    );
                  
                    else res.writeHead(500); res.end();
            
            else res.writeHead(500); res.end();
        
    

  connect.createServer(
    connect.cookieParser(),
    connect.bodyParser(),
    connect.session(secret:'wakajakamadaka'),
    passport.initialize(),
    passport.session(),
    checkLoggedIn).listen(8888);
  console.log('Server has started.');

有没有人有任何建议或发现我正在做的事情有问题?我的另外两个选择是切换回everyauth 并弄清楚那里发生了什么,或者切换到 ExpressJS,但我宁愿不使用其中任何一个选项。

最好的,萨米人

【问题讨论】:

【参考方案1】:

passport.authenticate 返回一个通常用于中间件链的函数,该函数由 Express 使用 reqres 调用。

它将在其他中间件或路由处理程序中独立工作,例如您的 checkLoggedIn 函数,但您必须显式调用以 reqresnext 返回的函数以使其处理请求。

else if(req.url == '/auth/facebook')
  // NOTE: call the function returned to process the request
  passport.authenticate('facebook')(req, res, next);
  return;

否则看起来不错。让我知道这是否能让您启动并运行。

更新

Jared 在 *** 之外帮助了我一点,我们已经完全解决了这个问题。我正在更新此答案以包含我们发现的新信息。

1) 一个问题显然是在 Express 中存在 redirect() 中间件,但在 Connect 中不存在(至少当前版本不存在)。使用connect时,您需要将PassportJS模块中authenticate.js的第97行从return res.redirect(options.successRedirect);更改为:

var redirect = function(redirectionURL)
    res.writeHead(302, 'location':redirectionURL);
    res.end();             


return redirect(options.successRedirect);

注意 - 上面的options.successRedirect 与回调函数代码中的successRedirect 相同。这将是我问题代码中的passport.authenticate('facebook', failureRedirect: '/failbook', successRedirect:'/'); 行。

2) 另一个是我在我的应用程序中使用集群模块(不是我上面的代码 sn-p 中显示的东西)。这意味着 nodeJS 应用程序没有正确读取会话数据,这导致了我的问题。 此问题将影响任何依赖会话的库,包括所有其他使用会话的身份验证模块(例如everyauth、connect-auth 等)我将引用 Jared 的解决方案:

快速回复:您是使用集群还是启动多个服务器 实例?

如果是这样,会话的内置 MemoryStore 将无法正常工作, 你需要切换到这样的东西: https://github.com/visionmedia/connect-redis

或此处列出的其他会话存储之一: https://github.com/senchalabs/connect/wiki

原因是您最终会访问没有服务的服务器 原始请求,因此没有该会话信息 在自己的记忆中。这听起来像会发生什么,如果 没有 100% 的时间调用 deserializeUser。

希望这可以帮助到这里的人!

【讨论】:

嗯,我比以前走得更远了,但它还没有完全发挥作用。现在我正在注册来自 facebook 的回调。我现在正在对照 req.url.split('?')[0] 检查'/auth/facebook/callback',以便回调注册。在函数调用后添加 (req,res,next) 会导致无限重定向循环。有什么想法吗? 我认为您需要在 createServer 中间件设置中使用 connect.query() 中间件。 Passport 期望在很多情况下填充req.query,包括在 Facebook 回调中获取授权码。 几乎就在那里......在回调身份验证调用的末尾添加了(req,res,next),使用正确的facebook数据到达facebook响应函数。但是,我得到了TypeError: Object #<ServerResponse> has no method 'redirect'。有问题的代码行是authenticate.js 的第97 行上的return res.redirect(options.successRedirect);。知道问题可能是什么吗? 显然问题是 connect 没有 redirect() 中间件,而 express 有。我已经用我自己的返回函数替换了那行,它实现了同样的事情。 facebook 数据现在可以正常工作,并且 facebook 返回的标准 '#_=_' 会到达浏览器。但是,对于未来的请求,req.user 仍然未定义。关于可能导致这种情况的任何想法?我必须在任何时间点调用 serializeUser 吗? 如果一切正常,Passport 应该调用您的 serializeUser/deserializeUser 函数。你可以在那里添加日志语句来验证它是否是,以及它得到的参数。另外,我很好奇fbUserData 是否包含登录后的用户信息。让我知道那些东西。渴望让您启动并运行!

以上是关于使用 PassportJS 和 Connect for NodeJS 来验证 Facebook 用户的主要内容,如果未能解决你的问题,请参考以下文章

NodeJS ExpressJS PassportJS - 仅用于管理页面

NodeJS ExpressJS PassportJS - 仅用于管理页面

如何使用来自passportjs的会话

同时使用 JWT 和 Passportjs

SANE 堆栈和 Passportjs

PassportJs 身份验证无限循环和执行(默认)查询