我正在尝试使用node-openid(通过passport-google)通过Google凭据对我的用户进行身份验证。它在我的开发机器上工作正常但是当我用2个dynos将它部署到Heroku时,当一个dyno处理整个OpenID会话时它会起作用,而当一个dyno上启动会话并且在第二个dyno上完成会话时失败。在这种情况下,我收到以下错误:
2013-01-15T15:18:24+00:00 app[web.2]: Failed to verify assertion (message: Invalid association handle)
2013-01-15T15:18:24+00:00 app[web.2]: at Strategy.authenticate.identifier (/app/node_modules/passport-google/node_modules/passport-openid/lib/passport-openid/strategy.js:143:36)
...
处理此问题的正确方法是什么?我是否应该以某种方式在数据库中保存对话状态,以便两个dynos都可以访问它?
更新
这是我用来通过在MongoDB中存储关联来解决问题的代码。
var
GoogleStrategy = require('passport-google').Strategy;
// We have to save the OpenID state in the database so it's available to both
// dynos.
db.collection('OpenID').ensureIndex({expires: 1}, {expireAfterSeconds: 0},
function(err, result) {
if (err) {
throw new Error('Error setting TTL index on OpenID collection.');
}
});
// Use the GoogleStrategy within Passport.
// Strategies in passport require a `validate` function, which accept
// credentials (in this case, an OpenID identifier and profile), and invoke a
// callback with a user object.
strategy = new GoogleStrategy({
returnURL: 'http://localhost:3000/auth/google/return',
realm: 'http://localhost:3000/'
},
function(identifier, profile, done) {
// asynchronous verification, for effect...
process.nextTick(function () {
// To keep the example simple, the user's Google profile is returned to
// represent the logged-in user. In a typical application, you would want
// to associate the Google account with a user record in your database,
// and return that user instead.
profile.identifier = identifier;
return done(null, profile);
});
}
);
strategy.saveAssociation(function(handle, provider, algorithm, secret, expiresIn, done) {
db.collection("OpenID").insert({
handle: handle,
provider: provider,
algorithm: algorithm,
secret: secret,
expires: new Date(Date.now() + 1000 * expiresIn)
}, done);
});
strategy.loadAssociation(function(handle, done) {
db.collection("OpenID").findOne({handle: handle}, function (error, result) {
if (error)
return done(error);
else
return done(null, result.provider, result.algorithm, result.secret);
});
});
答案 0 :(得分:5)
您应该查看node-openid README中的Storing association state部分。默认情况下,会话状态存储在各个dynos的内存中,这就是导致问题的原因。
重写saveAssociation()
和loadAssociation()
mixins以使用您的应用程序当前使用的任何后备存储。还有更多documentation in the passport-openid source code。