4

node-openidpassport-google経由)を使用して、Googleのクレデンシャルでユーザーを認証しようとしています。開発マシンでは正常に動作しますが、2つのdynoを使用してHerokuにデプロイすると、1つのdynoがOpenID会話全体を処理するときに機能し、会話が1つのdynoで開始され、2番目の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)
...

これを処理する正しい方法は何ですか?両方のdynoがアクセスできるように、会話の状態をデータベースに保存する必要がありますか?

アップデート:

これは、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);
    });
});
4

1 に答える 1

5

node-openidREADMEのStoringassociationstateセクションを確認する必要があります。デフォルトでは、セッション状態は個々のdynoのメモリに保存され、それが問題の原因です。

saveAssociation()およびミックスインをオーバーライドしてloadAssociation()、アプリケーションが現在使用しているバッキングストアを使用します。passport-openidソースコードにはさらに多くのドキュメントがあります。

于 2013-01-15T21:34:09.333 に答える