node.js - 由于 Chrome 预加载导致 Passport FacebookTokenError

标签 node.js facebook google-chrome preloading passport.js

我正在开发一个网络应用程序,它允许用户使用 Passport.js 通过 Facebook 登录。我的代码如下:

/* Passport.js */
var passport = require('passport');
var FacebookStrategy = require('passport-facebook').Strategy;

/* DB */
var User = require('../models/db').User;

exports.passport = passport;

passport.use(new FacebookStrategy(
  {
    clientID: '<ID>',
    clientSecret: '<SECRET>',
    callbackURL: 'http://localhost:4242/auth/facebook/callback'
  },
  function (accessToken, refreshToken, profile, done) {
    console.log(profile.provider);
    User.findOrCreate({ "provider": profile.provider,"id": profile.id },
                      function (err, user) { return done(err, user); });
  }
));

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

passport.deserializeUser(function(id, done) {
  console.log('deserialize');
  User.findOne({"id": id}, function(err, user) {
    done(err, user);
  });
});

此代码在 Firefox 上运行良好;我的用户通过 Facebook 进行身份验证,然后成功路由。但是,在 Chrome 上,我有时会收到以下错误:

FacebookTokenError: This authorization code has been used.
at Strategy.parseErrorResponse (/Users/Code/Web/node_modules/passport-facebook/lib/strategy.js:198:12)
at Strategy.OAuth2Strategy._createOAuthError (/Users/Code/Web/node_modules/passport-facebook/node_modules/passport-oauth2/lib/strategy.js:337:16)
at /Users/Code/Web/node_modules/passport-facebook/node_modules/passport-oauth2/lib/strategy.js:173:43
at /Users/Code/Web/node_modules/passport-facebook/node_modules/passport-oauth2/node_modules/oauth/lib/oauth2.js:162:18
at passBackControl (/Users/Code/Web/node_modules/passport-facebook/node_modules/passport-oauth2/node_modules/oauth/lib/oauth2.js:109:9)
at IncomingMessage.<anonymous> (/Users/Code/Web/node_modules/passport-facebook/node_modules/passport-oauth2/node_modules/oauth/lib/oauth2.js:128:7)
at IncomingMessage.EventEmitter.emit (events.js:117:20)
at _stream_readable.js:910:16
at process._tickCallback (node.js:415:13)

我的打印语句揭示了一些相当意外的行为,如下图所示:

未完成的URL等待提交...

The unfinished URL waiting to be submitted...

...在我的终端中生成打印语句。 ...results in print statements in my terminal

Chrome 似乎试图将请求预加载到 Facebook,如果客户端在正确的时间按下 enter,则会导致竞争条件并导致错误,如下所示:

An example of the error

我已经用 Wireshark 确认了多个请求。如果我在自动完成和提交 URL 之间等待足够长的时间(比如 3 秒),两个请求都会无误地完成。仅当两个请求仅相隔一秒多一点时才会发生该错误。该错误是 Chrome 独有的,因为 Firefox 只发送一个请求。

这里有什么我可以做的吗?当涉及到像 Facebook 身份验证这样频繁的事情时,我的应用程序肯定不会是唯一遇到此错误的应用程序。我可以以某种方式阻止 Chrome 预加载吗?如果没有,我是不是只能接受错误并再次尝试进行身份验证?

奖金问题:我似乎为每个请求反序列化多次。我的第一个请求将打印以下内容:

facebook
serialize
deserialize

每个后续成功的请求打印

deserialize
deserialize
facebook
serialize
deserialize

不成功的请求对打印

deserialize
deserialize
deserialize
deserialize
/* Error */
facebook
serialize

看起来每个请求都反序列化了两次。我读了this bug report建议一个解决方案,但 express.static 确实在我的中间件堆栈中出现在 passport.session 之前,所以这不是我的问题。

谢谢!

最佳答案

我会把它留作评论,但我没有名气。但是 Chrome 只会在您在 URL 栏中输入内容时预取页面,但是您或用户为什么要手动输入 /auth/facebook

一个可能的解决方案是让 /auth/facebook 路由只接受 POST 请求。这将使 Chrome 在尝试预加载时无法触发路由。

另一种可能的解决方案,我不确定它的效果如何,需要查询字符串中的时间戳,例如 /auth/facebook?_t=1406759507255。并且仅在时间戳与当前时间足够接近时调用 passport.authenticate('facebook')。但我认为这两种解决方案都不是必需的,因为根本没有人应该输入该 URL。

关于node.js - 由于 Chrome 预加载导致 Passport FacebookTokenError,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21446460/

相关文章:

android - 此应用未配置 Android key 哈希。 - 使用 Facebook SDK 登录

javascript - jssor : bug in full-width-slider. html

java - 我们可以通过编程方式配置 Chrome 吗?

javascript - file[i] === 10 是什么意思?

node.js - nuxt generate 不生成index.html

php - 使用 HybridAuth 的 Facebook 登录显示错误您无法直接访问此页面

ios - Facebook iOS SDK 3.1 在后续调用 FBSession openWithBehavior 时崩溃

javascript - 在 Node 中使用 module.exports 以获得更好的结构

Node.JS 字符串数组排序不起作用

google-chrome - chrome应用程序webview事件定义和顺序