Node.js Экспресс-выпуск Cookie Паспорта

Я использую 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. Затем происходит перенаправление, запрос новый не имеет сохраненной информации о сеансе и имеет совершенно новый идентификатор сеанса. Я подозревал, что на клиенте не было установлено никакого файла cookie, и это похоже на то, что должно объяснять отсутствие последовательных сеансов.

Однако я не могу понять , почему не установлен новый файл cookie. Что-то не так, как настроено приложение, которое указывает, почему это происходит?

Я должен добавить, что перезапуск экземпляра Node.js исправляет проблему, это просто не то, что было бы допустимым в процессе производства.

Спасибо.

UPDATE. Я запустил Fiddler, чтобы узнать, что происходит с трафиком HTTP/S, и я вижу, что когда он работает изначально, я получаю набор cookie в браузере (я попробовал несколько), который затем передается обратно на сервер при последующих запросах.

Когда он не работает, браузер не передает файлы cookie на сервер, поэтому Node отправляет заголовок Set-Cookie, каждый раз предоставляющий новый файл cookie. До сих пор мне не удавалось определить причину этого.

Ответы

Ответ 1

Я понял это, хотя мне не нравится ответ.

ТЛ; дг; - используйте maxAge вместо истечения срока действия.


Проблема была внедрена в дату истечения срока действия, установленную для каждого файла cookie (который автоматически устанавливается Express). Я заметил, что каждый cookie, который был установлен, имеет одинаковую дату истечения срока действия, которая в конечном итоге оказалась в прошлом и, следовательно, мгновенно истекала.

Причина этого была здесь:

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

Новая дата создавалась только один раз, при запуске сервера. Это привело к тому, что срок годности был одинаковым каждый раз. Основываясь на коде в исходном сообщении, я не могу понять, почему он не работает, и все же каждый пример, который я нашел в Интернете, использует тот же самый код. Я проверил это, указав функцию, создавшую эту дату, и проверил, что она вызвана только при запуске сервера.

Чтобы исправить эту проблему, я определяю maxAge вместо "expires". 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);
});

Ответ 2

Задайте имя файла cookie для значения, где может быть строка или объект, преобразованный в JSON. Параметр пути по умолчанию имеет значение "/".

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

Опция maxAge является удобной опцией для установки "expires" относительно текущего времени в миллисекундах. Следующий пример эквивалентен предыдущему примеру.

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

Также ссылка

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