【发布时间】:2014-02-22 03:55:54
【问题描述】:
我正在开发一个允许用户使用 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)
我的打印语句揭示了一些相当意外的行为,如下图所示:
等待提交的未完成网址...
...在我的终端中产生打印语句。
Chrome 似乎尝试将请求预加载到 Facebook,如果客户端在正确的时间按下回车,则会导致竞争条件导致错误,如下所示:
我已通过 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 之前,所以这不是我的问题。
谢谢!
【问题讨论】:
标签: node.js facebook google-chrome preloading passport.js