护照认证回调挂起

Posted

技术标签:

【中文标题】护照认证回调挂起【英文标题】:Passport authentication callback hangs 【发布时间】:2015-12-13 16:44:21 【问题描述】:

几个小时后,我试图自己解决这个问题,我到 SO 社区寻找一些光明。

我正在使用护照进行用户身份验证。根据文档,它已经在我的主 express.js 文件中初始化:

app.use(passport.initialize());

我有一个 index.js 文件,它以这种方式处理 facebook-passport: 索引.js

'use strict';

import express from 'express';
import passport from 'passport';
import auth from '../auth.service';
let router = express.Router();

//this function is defined in the auth.service import but copied it here in case it's needed (the `signToken` is also defined in the service)
function setTokenCookie(req, res) 
  if (!req.user) return res.json(404,  message: 'Something went wrong, please try again.');
  var token = signToken(req.user._id, req.user.role);
  res.cookie('token', JSON.stringify(token));
  res.redirect('/');



router
  .get('/', passport.authenticate('facebook', 
    scope: ['email', 'user_about_me'],
    failureRedirect: '/login'
  ))

.get('/callback', passport.authenticate('facebook', 
  successRedirect: '/',
  failureRedirect: '/login'
), setTokenCookie);

module.exports = router;

以这种方式在 index.js 中导入的 passport.js:

passport.js

import passport from 'passport';
import 
  Strategy as FacebookStrategy

from 'passport-facebook';

exports.setup = function(User, config) 
  passport.use(new FacebookStrategy(
      clientID: config.facebook.clientID,
      clientSecret: config.facebook.clientSecret,
      callbackURL: config.facebook.callbackURL
    ,
    function(accessToken, refreshToken, profile, done) 
      User.findOne(
        'facebook.id': profile.id
      , (findErr, user) => 
        if (findErr) 
          return done(findErr);
        
        if (!user) 
          let userToSave = new User(
            name: profile.displayName,
            email: profile.emails[0].value,
            role: 'user',
            username: profile.username,
            provider: 'facebook',
            facebook: profile._json
          );
          userToSave.save((saveErr) => 
            if (saveErr) done(saveErr);
            return done(null, user);
          );
         else 
          return done(null, user);
        
      );
    
  ));
;

这是目前发生的情况:

Facebook 登录提示 在 Facebook 中成功验证后,回调 (/auth/facebook/callback) 将按预期使用用户信息和令牌到达。 用户保存在带有预期字段的数据库中

事情变得奇怪的地方:

保存用户后,done(null,user) 什么也不做。应用程序挂起回调,客户端一直等待响应。 中间件 setTokenCookie 永远不会被调用,所以问题肯定出在上一步。

我尝试过的:

将来自 passport.js 的整个设置函数封装在一个 process.tick 中(发现有人使用它但没有解决问题) 在 User.findOne(...).exec().then(user => ...) 中使用带有 Promise 的 Mongoose

如果您需要更多信息,请随时提出。非常感谢任何帮助。

谢谢!

【问题讨论】:

你调用了 mongoose.connect() 吗? 是的:)。关于 Mongoose 的所有内容都按预期工作,用户要么已保存,要么从数据库中检索,但在这两种情况下,当 done(null, user) 被调用时,它都会挂起。 您如何确定 setTokenCookie 没有执行?你到处都有console.logs吗? 我迷上了节点调试,我也尝试过使用 console.log()。但无论如何,如果它被执行,我至少会得到一些回应。 这个你搞定了吗?我遇到了同样的问题,现在我无法入睡。 【参考方案1】:

我看到我的代码有一些可能丢失的部分。你在使用passport.session() 中间件吗?还有serializeUserdeserializeUser 函数?

passport.serializeUser(function(user, done) 
  //place user's id in cookie
  done(null, user.id);
);

passport.deserializeUser(function(id, done) 
  //retrieve user from database by id
  User.findById(id, function(err, user) 
    done(err, user);
  );
);

【讨论】:

你好@cody。是的,我尝试使用 passport.session() 并删除它并将 session: false 选项添加到 Passport 策略。关于那些函数,它们被调用了吗?有必要吗? serializeUser 将在用户通过 facebook 成功登录后调用,以使 cookie 中的 user.id 可用于后续请求。 deserializeUser 用于这些后续请求,以允许您从数据存储中检索用户。我相信您想通过passport.session() 中间件在您的场景中使用它们。我很确定护照希望它们用于所有服务,除了您为每个请求发送凭据的服务(通常是 API)。【参考方案2】:

如果您像我一样是护照/快递的菜鸟,这可能会有所帮助:

检查您是否在护照逻辑中调用了 done():

passport.use(new twitchStrategy(
    clientID: config.twitchID,
    clientSecret: config.twitchSecret,
    /*to be updated*/
    callbackURL: config.callbackURL,
    scope: "user_read"
  ,
  function(accessToken, refreshToken, profile, done) 
    console.log(profile);
    ***return done();***
  
));

【讨论】:

以上是关于护照认证回调挂起的主要内容,如果未能解决你的问题,请参考以下文章

护照认证失败导致重定向循环

护照 jwt 验证回调未调用

Mongoose“创建”方法 - 没有回调吗? (使用护照和角度)

关于护照序列化/反序列化用户中的回调函数的困惑

在护照 app.use() 回调中未收到 Req 和 Res 参数

未达到异步回调,响应挂起