由于Chrome预加载导致护照FacebookTokenError

我正在开发一个Web应用程序,允许用户使用Passport.js通过Facebooklogin。 我的代码如下:

/* 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进行身份validation,然后成功路由。 但是,在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…

等待提交的未完成的网址...

…在我的terminal打印报表。 ...在我的终端打印报表

看起来,Chrome尝试将请求预加载到Facebook,导致竞争状态,如果客户端在恰当的时间按下input,导致错误,如下所示:

错误的一个例子

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

我能在这里做什么吗? 我的应用程序肯定不能是唯一一个经历这个错误,当涉及到像Facebook身份validation频繁的事情。 我可以阻止Chrome预加载吗? 如果不是的话,我是否已经辞职去捕捉错误,然后试图再次进行validation?

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

 facebook serialize deserialize 

每一个后续的成功请求打印

 deserialize deserialize facebook serialize deserialize 

而不成功的请求对打印

 deserialize deserialize deserialize deserialize /* Error */ facebook serialize 

它看起来像每个请求反序列化两次。 我读了这个bug报告,提出了一个解决scheme,但express.static确实在passport.session之前出现在我的中间件堆栈中,所以不能成为我的问题。

谢谢!

我会留下这个评论,但我没有声誉。 但是,Chrome只会在url列中input内容时预取网页,但为什么您或用户需要手动input/auth/facebook

一个可能的解决scheme是使/auth/facebook路由只接受POST请求。 这会阻止Chrome在尝试预加载时触发路由。

另一个可能的解决scheme,我不知道这将如何工作,将需要查询string,像/auth/facebook?_t=1406759507255 。 只有当时间戳足够接近当前时间时才调用passport.authenticate('facebook') 。 但是我不认为这些解决scheme中的任何一个都是必要的,因为根本没有人应该input那个URL。