17

アプリでの認証に Passport を使用しており、Express も使用しています。私の問題を要約すると、ログイン機能は最初は正常に機能しますが、ユーザーのセッションがタイムアウトした後ユーザーはログインできなくなります。

認証に標準のローカル戦略を使用しています。

私のセットアップに基づいて、できるだけ単純な例を含めます。

//-------------
//Set up authentication with Passport
//-------------
var userModel = require('./models/user')(db);
passport.use(new LocalStrategy(
    function(username, password, done) {
        var errorMessage = 'Incorrect username/password combination.';
        userModel.GetUserByUsername(username, function(err, user) {
            if (err) { return done(err); }
            if (!user) {
              return done(null, false, { message: errorMessage });
            }

            user.validatePassword(password, function(isPasswordCorrect) {
                if (!isPasswordCorrect)
                {
                    return done(null, false, { message: errorMessage });
                }

                //Update with login date
                userModel.UpdateUserWithLogin(username, user.currentLoginTime, function(err){
                    //if we have an error here, we should probably just log it
                    if(err)
                    {
                        console.log(err);
                    }
                });

                return done(null, user);
            });
        });
    }
));

passport.serializeUser(function(user, done) {
  done(null, user);
});

passport.deserializeUser(function(user, done) {
    userModel.GetUserByUsername(user._id, function(err, user) {
            done(err, user);
        });
});

//-------------
//Set up express and configure
//-------------
var sessionStore = new SkinStore(db);
var app = express();

app.configure(function(){
    app.set('port', process.env.PORT || 3000);
    app.set('views', __dirname + '/views');
    app.engine('html', consolidate.swig);
    app.set('view engine', 'html');
    swig.init({
        root: '.',
        allowErrors: true, // allows errors to be thrown and caught by express instead of suppressed
        autoescape: false});

    app.use(express.logger('dev'));

    app.use(express.bodyParser());
    app.use(express.methodOverride());
    app.use(express.cookieParser("[mysecrethere]"));
    app.use(express.session({   store: sessionStore,
                            cookie: { expires : new Date(Date.now() + 3600000) } //1 Hour
                            }));
    app.use(passport.initialize());
    app.use(passport.session());
    app.use(flash());
    app.use(expressValidator);

    app.use(express.static(path.join(__dirname, 'public')));

    //Dynamic helpers
    app.use(require('./helpers/DynamicHelpers'));

    app.use(app.router);
});

app.get('/login', routes.login);
app.post('/login', passport.authenticate('local', {failureRedirect: '/login',
                                               badRequestMessage: "Please enter username and password",
                                               failureFlash: true }),
                                               function(req, res) {
                                                    var targetUrl = req.session.pageAfterLogin;
                                                    delete req.session.pageAfterLogin;
                                                    res.redirect(targetUrl || '/account');
                                                });

app.get('/account', IsAuthenticated, routes.account.show);

IsAuthenticated ヘルパー関数:

function IsAuthenticated(req,res,next){
    if(req.isAuthenticated())
    {
        next();
    }
    else
    {
        //save the requested page and then redirected
        req.session.pageAfterLogin = req.url;
        req.flash("error", "You must be logged in first!");
        res.redirect('/login');
    }
}

デバッグでわかることは、認証が成功した後 (および Cookie の有効期限が切れた後)、次のロジックにヒットしたことです (上記から)。

function(req, res) {
    var targetUrl = req.session.pageAfterLogin;
    delete req.session.pageAfterLogin;
    res.redirect(targetUrl || '/account');
}

「req」でセッションが適切に設定され、Passport 情報が適切に保存されていることがわかります。その後、リダイレクトが発生し、新しいリクエストにはセッション情報が保存されず、まったく新しいセッション ID が割り当てられます。クライアントに Cookie が設定されていないのではないかと疑っていましたが、そのように見えます。これは、一貫したセッションの欠如を説明するはずです。

ただし、新しい Cookie が設定されていない理由がわかりません。これが起こっている理由を示すアプリの構成方法に何か問題がありますか?

Node.js インスタンスを再起動すると問題が解決することを付け加えておきます。これは、本番環境で許容できるものではありません。

ありがとう。

更新: HTTP/S トラフィックで何が起こっているかを確認するために Fiddler を実行しました。最初に機能したときに、ブラウザーに設定された Cookie を取得していることがわかります (いくつか試しました)。その後のリクエスト。

それが機能しない場合、ブラウザーはサーバーに Cookie を渡していないため、Node は毎回新しい Cookie を提供する Set-Cookie ヘッダーを送信しています。これまでのところ、この原因を特定することはできませんでした。

4

2 に答える 2

29

私は答えが好きではありませんが、私はそれを理解しました。

tl; dr; -expiresの代わりにmaxAgeを使用します。


この問題は、各Cookie(Expressによって自動的に設定される)に設定された有効期限に起因していました。設定されたすべてのCookieの有効期限が同じであることに気付きましたが、最終的には過去のものになり、すぐに有効期限が切れます。

その原因はここにありました:

cookie: { expires : new Date(Date.now() + 3600000) }

新しい日付は、サーバーの起動時に1回だけ作成されていました。そのため、賞味期限は毎回同じになりました。元の投稿のコードに基づいて、なぜそれが機能しないのか理解できませんが、オンラインで見つけたすべての例でまったく同じコードが使用されています。この日付を作成した関数を定義し、サーバーの起動時にのみ呼び出されることを確認することで、これを確認しました。

この問題を修正するために、「expires」ではなくmaxAgeを定義しています。maxAgeは日付ではなくミリ秒数かかり、すべてのCookieに有効期限が正しく設定されているようです。

他の人がうまく使っているように見えるので、そもそもなぜこれが起こっているのか誰かが説明できるかどうか聞いてみたいです。何かご意見は?

以下の私の作業コードを参照してください

app.configure(function(){
    app.set('port', process.env.PORT || 3000);
    app.set('views', __dirname + '/views');
    app.engine('html', consolidate.swig);
    app.set('view engine', 'html');
    swig.init({
        root: '.',
        allowErrors: true, // allows errors to be thrown and caught by express instead of suppressed
        autoescape: false});

    app.use(express.logger('dev'));

    app.use(express.bodyParser());
    app.use(express.methodOverride());
    app.use(express.cookieParser("[mysecrethere]"));
    app.use(express.session({   store: sessionStore,
                            cookie: { maxAge : 3600000 } //1 Hour
                            }));
    app.use(passport.initialize());
    app.use(passport.session());
    app.use(flash());
    app.use(expressValidator);

    app.use(express.static(path.join(__dirname, 'public')));

    //Dynamic helpers
    app.use(require('./helpers/DynamicHelpers'));

    app.use(app.router);
});
于 2013-02-28T05:14:33.940 に答える
-2

cookie 名を値に設定します。これは、文字列または JSON に変換されたオブジェクトです。パス オプションのデフォルトは「/」です。

res.cookie('rememberme', '1', { expires: new Date(Date.now() + 900000), httpOnly: true });

maxAge オプションは、ミリ秒単位の現在の時刻に関連する「有効期限」を設定するための便利なオプションです。以下は、前の例と同等です。

res.cookie('rememberme', '1', { maxAge: 900000, httpOnly: true })

リンクも

http://expressjs.com/api.html#res.cookie

于 2013-08-21T09:27:51.963 に答える