req.session.user удаляется, пока пользователь активен

Я установил время ожидания сеанса на 30 минут. Пока я еще активен, req.session.user удаляется через 30 минут. Тем не менее, сессия все еще жива. Вот мой конфиг (использую экспресс-сессию и паспорт.js):

app.use(session({
    store: new RedisStore({client: <my client>, disableTTL: true}),
    secret: <some_secret>,
    resave: true,
    saveUninitialized: false,
    cookie: {maxAge: 1800000}
}));

app.use(passport.initialize());
app.use(passport.session());

// Are these serializer/deserializer needed?
passport.serializeUser((user, done) => {
    done(null, user);
});
passport.deserializeUser((user, done) => {
    done(null, user);
});

В логине:

router.post('/login', (req, res, next) => {
    passport.authenticate('ldapauth', {session: false}, (err, user, info) => {
        ...
        if (user) {
            req.session.user = {email: req.body.username};
        }
        next();
    })(req, res);
});

Код подтверждения выглядит следующим образом:

isLoggedIn() {
    if (req.session && req.session.user) {
        return true;
    }
    return false;
}

Я установил req.session.user на какой-то объект после успешного входа в систему.

Итак, через 30 минут req.session.user удаляется, но req.session все еще существует и продолжает увеличивать дату истечения срока действия, так как я все еще активно работаю над страницей.

Почему req.session.user удаляется через 30 минут? Думал паспорт едет на сеанс экспрессом?

* ОБНОВЛЕНИЕ * Сначала я подумал, что срок действия увеличивается, но это не так. Раньше я ставил resave: false. Затем, когда я регистрирую сеанс, срок действия всегда одинаков:

Session {
    cookie:
         { path: '/', _expires: <some date>.... }
    user:
         { email: <the one i set before>, sessionId: <some id> } }

Затем через 30 минут пользователь удаляется. Только в этот момент срок действия начинает увеличиваться.

Session {
    cookie:
         { path: '/', _expires: <some date>.... }

Затем я прочитал кое-что о методе touch, который вызывает экспресс-сеанс. В документации сказано, что если магазин реализует этот метод touch, то можно установить resave: false. Итак, думая, что Redis, возможно, не реализует этот метод, я попытался установить resave: true. Затем, когда я регистрирую сеанс, я заметил, что срок действия теперь увеличивается, по сравнению с предыдущим, который увеличивается только после удаления пользователя. Однако через 30 минут снова пользовательский ключ удаляется.

Затем по предложению Нири я установил disableTTL: true. Опять произошло то же самое.

В Redis я пытаюсь получить ключ. До истечения 30 минут срок действия в Redis увеличивается:

127.0.0.1:6379> mget sess:<some id>

1) "{\"cookie\":{\"originalMaxAge\":1800000,\"срок действия\":\"2018-11-15T06:04:26.994Z\",\"httpOnly\":true,\" path\":\"/\"},\"user\":{\"email\":\"[email protected]\",\"sessionId\":\"некоторый идентификатор сеанса\"}}"

Затем, через 30 минут, я посмотрел на Redis, ключ сеанса все еще там, но он перестал увеличивать срок действия. В то время как req.session по-прежнему увеличивает срок действия, но с удалением свойства пользователя.


person iPhoneJavaDev    schedule 08.11.2018    source источник
comment
Пожалуйста, опубликуйте параметры Redis. Я подозреваю, что вы установили срок действия данных.   -  person niry    schedule 11.11.2018
comment
Я не устанавливал срок действия Redis. В параметрах я предоставляю только клиент для подключения. Кроме того, даже когда я столкнулся с тайм-аутом, идентификатор сеанса остается в Redis.   -  person iPhoneJavaDev    schedule 11.11.2018
comment
Просто чтобы уточнить, с тайм-аутом, я имею в виду, что req.session.user, который я установил, был удален через 30 минут, пока он все еще был активен. Я думаю, что-то происходит с паспортом, может быть, я не уверен.   -  person iPhoneJavaDev    schedule 11.11.2018


Ответы (1)


Почему req.session.user удаляется через 30 минут?

Поскольку параметр maxAge файла cookie установлен на 1800000 мс, что составляет 30 минут. Таким образом, браузер (или любой другой клиент, который вы используете) удалит файл cookie через 30 минут.

Сеанс — это некоторая информация, которую вы хотите сохранить при последующих запросах. Как правило, сеанс имеет идентификатор (идентификатор сеанса) и связанную с ним полезную нагрузку. Когда вы делаете req.session = { ... }, промежуточное ПО express-session возьмет объект, сгенерирует идентификатор и сохранит его в указанном вами store. (RedisStore в вашем случае). Итак, теперь ваша «база данных» имеет сопоставление sessionID и payload.

Файлы cookie — это то, что после отправки с сервера будет каждый раз пересылаться на этот сервер (в этот домен) для каждого последующего запроса, пока не истечет срок их действия. Обратите внимание, что как только файл cookie получен, клиент должен управлять им. Сгенерированный sessionID вместе с подписью отправляется клиенту в файле cookie.

Как только файл cookie будет сохранен на вашем клиенте. Он будет перенаправлен со следующим запросом. Когда ваше промежуточное ПО express-session увидит файл cookie, оно извлечет sessionID из файла cookie и попытается найти соответствующую полезную нагрузку в store (в вашем случае RedisStore). Затем полезная нагрузка устанавливается на req.session вместе с другой информацией.

По истечении срока действия клиент удалит файл cookie. Таким образом, запрос от этого клиента не будет иметь куки. Поскольку файла cookie нет, express-session не сможет установить req.session, и можно подумать, что пользователь вышел из системы. Обратите внимание, что хранилище по-прежнему содержит сопоставление sessionID, payload, которое будет удалено в соответствии с конфигурацией ttl для store.


Думаю, путаница возникла в первую очередь из-за поля session.cookie. session.cookie всегда будет там благодаря промежуточному программному обеспечению express-session.

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


Я прикладываю пример кода к tinker. Конечная точка set-cookie установит файл cookie, срок действия которого истекает через 20 секунд. Конечная точка get-cookie получит данные cookie и session.

Надеюсь, это поможет!

const express = require("express");
const session = require("express-session");
const cookieParser = require("cookie-parser");
const FileStore = require("session-file-store")(session);
const path = require("path");

const app = express();

app.use(express.json());

app.use(cookieParser());
app.use(
    session({
        secret: "top secret!",
        resave: false,
        rolling: true,
        saveUninitialized: false,
        cookie: {
            maxAge: 20 * 1000
        },
        name: "demo",
        store: new FileStore({
            path: path.join(__dirname, "../sessions"),
            retries: 1,
            fileExtension: ".json"
        })
    })
);

app.use("/set-cookie", (req, res) => {
    req.session.payload = { foo: "bar", timestamp: new Date().toISOString() };
    res.json({ message: "done" });
});

app.use("/get-cookie", (req, res) => {
    res.json({
        sessionID: req.sessionID,
        session: req.session,
        cookies: req.cookies,
        timestamp: new Date().toISOString()
    });
});

app.listen(3000, err => {
    if (err) {
        throw err;
    }
    console.log("demo app listening on port 3000");
});

ОБНОВЛЕНИЕ На основании комментариев, что вы ищете rolling вариант. Как только вы установите rolling: true в express-session, сеанс будет обновляться для каждого запроса. И пользователь выйдет из системы через maxAge ИДЕАЛЬНОГО времени.

Я обновил код.

person Anand Undavia    schedule 15.11.2018
comment
Извините, но я еще больше запутался. Я думаю, что понимаю часть файла cookie сеанса между клиентом и сервером. Дело в том, что пользователь все еще активен, а срок действия увеличивается. - person iPhoneJavaDev; 15.11.2018
comment
Что именно вы подразумеваете под пользователем, который все еще активен? Как я уже сказал, срок действия — это время, когда истечет срок действия файла cookie, если он установлен в этом запросе. - person Anand Undavia; 15.11.2018
comment
Таким образом, вы всегда будете видеть expires at = current time + maxAge независимо от того, установлен файл cookie или нет. Попробуйте - person Anand Undavia; 15.11.2018
comment
Моя цель: когда пользователь простаивает в течение 30 минут, срок действия сеанса истекает. Поэтому, когда пользователь попытается вызвать API, я выдам ошибку, поскольку срок его сеанса уже истек. Но поскольку пользователь все еще активно вызывает API в течение 30 минут, я ожидаю, что срок действия сеанса будет увеличиваться. Например, пользователь бездействовал 5 минут, поэтому до истечения сеанса осталось 25 минут. Затем пользователь вызывает API, и время истечения срока действия сбрасывается до 30 минут. Глядя на redis и req.session, кажется, что он увеличивается, пока пользователь активен, чего я и ожидаю. - person iPhoneJavaDev; 15.11.2018
comment
Ааа хорошо теперь я понимаю это правильно. Я бы обновил ответ соответствующим образом, тем временем вы, возможно, захотите обновить вопрос и с этими деталями! - person Anand Undavia; 15.11.2018
comment
Чувак, я должен отдать это тебе. Вы правы, это катящаяся штуковина. Я просто не понимаю, почему по умолчанию это значение false. Я думал, что это обычное дело сбрасывать срок действия, когда пользователь активен. В любом случае, спасибо, что указали на это. - person iPhoneJavaDev; 15.11.2018
comment
Рад, что смог помочь! Кроме того, по умолчанию false уменьшает количество операций с базой данных. Подумайте об этом, каждый запрос означает как минимум один запрос к БД. На основе БД это может быть невозможно. Обычной практикой, которую я вижу, является установка maxAge в днях (30 дней) и rolling: false. - person Anand Undavia; 15.11.2018