данные сессии не хранятся для нескольких пользователей в таблице

Вопрос или проблема

Я использую passport для аутентификации и connect-pg-simple для хранения сеансов в базе данных PostgreSQL. Однако я столкнулся с проблемой, когда в базе данных, похоже, хранится только один сеансовый куки одновременно, независимо от того, сколько пользователей вошли в систему или зарегистрировались. Не уверен, перезаписывается ли старый, но даже после новой авторизации существует только одна строка.

Таблица сеансов существует, и каждый раз, когда я выполняю запрос select, я вижу только одну строку сеанса. Это стандартное поведение? Я ожидал, что новая строка будет добавлена после входа в систему с другой учетной записью.

Вот соответствующий код

app.use(express.urlencoded({ extended: true }));
app.use(
  session({
    secret: process.env.SESSION_SECRET,
    resave: false,
    saveUninitialized: false,
    cookie: {
      maxAge: 24 * 60 * 60 * 1000,
    },
    store: new pgSession({
      pool: pgPool,
      tableName: "session",
    }),
  })
);
app.use(passport.session());

passport.use(
  new LocalStrategy(async (username, password, done) => {
    try {
      const selectQuery = "SELECT * FROM users WHERE username=$1";
      const { rows } = await pgPool.query(selectQuery, [username]);
      const user = rows[0];

      if (!user) {
        return done(null, false, { message: "Неправильное имя пользователя" });
      }
      const cmpPassword = await bcrypt.compare(password, user.password);
      if (!cmpPassword) {
        return done(null, false, { message: "Неправильный пароль" });
      }
      return done(null, user);
    } catch (err) {
      return done(err);
    }
  })
);

passport.serializeUser((user, done) => {
  return done(null, user.id);
});

passport.deserializeUser(async (id, done) => {
  try {
    const selectQuery = "SELECT * FROM users WHERE id=$1";
    const { rows } = await pgPool.query(selectQuery, [id]);
    const user = rows[0];
    done(null, user || null);
  } catch (err) {
    done(err);
  }
});

app.get("/", (req, res) => {
  res.render("index", { user: req.user });
});

app.post(
  "/login",
  passport.authenticate("local", {
    successRedirect: "/",
    failureRedirect: "/signup",
  })
);

app.get("/signup", (req, res) => {
  res.render("signup");
});

app.post("/signup", async (req, res, next) => {
  try {
    if (req.isAuthenticated()) {
      req.logOut((err) => {
        if (err) {
          return next(err);
        }
      });
    }

    const { username, password } = req.body;
    const hashedPassword = await bcrypt.hash(
      password,
      Number(process.env.SIGNUP_HASH_SALT) || randint(10, 15)
    );
    const insertQuery =
      "INSERT INTO users (username, password) VALUES ($1, $2) RETURNING *;";
    const { rows } = await pgPool.query(insertQuery, [
      username,
      hashedPassword,
    ]);

    req.logIn(rows[0], (err) => {
      if (err) return next(err);
      res.redirect("/");
    });
  } catch (err) {
    console.error(err.message);
    res.redirect("/signup");
  }
});

Ответ или решение

Проблема, с которой вы столкнулись, связана с тем, что в вашей базе данных PostgreSQL хранится только одна сессия для всех пользователей. Это не является нормальным поведением для системы аутентификации и хранения сессий. Рассмотрим основные причины такой проблемы и возможные пути её решения.

1. Конфигурация сессий

Ваша сессия хранится с помощью connect-pg-simple, однако важно убедиться, что вы корректно настраиваете параметры store и их использование. Ваша текущая конфигурация выглядит корректной на первый взгляд:

app.use(session({
  secret: process.env.SESSION_SECRET,
  resave: false,
  saveUninitialized: false,
  cookie: {
    maxAge: 24 * 60 * 60 * 1000,
  },
  store: new pgSession({
    pool: pgPool,
    tableName: "session",
  }),
}));

Тем не менее, следует обратить внимание на параметры resave и saveUninitialized. Чтобы новые сессии добавлялись в базу данных при каждом входе пользователя, saveUninitialized должно быть установлено в true.

2. Ведение сессий

Параметр resave отвечает за сохранение в базе данных неперезаписанных сессий. Если resave установлен в false, а сессия не изменяется, то она не будет сохранена. Установка resave в true позволит убедиться, что все сессии, а не только обновленные, сохраняются при каждой аутентификации.

3. Проверка механизма аутентификации

Если у вас уже есть сессия пользователя и вы пытаетесь войти заново с другим пользователем, то важно убедиться, что вы вызываете req.logout() перед тем, как попытаться войти снова. В вашем коде используется эта функция в обработчике POST /signup, но важно убедиться, что между входами в систему создается чистая сессия.

4. Логирование и отладка

Рекомендуется добавить логирование в соответствующие области вашего кода. Например, можно добавить вывод в консоль при каждом создании сессии. Это позволит вам увидеть, когда новые сессии создаются или не создаются:

app.use((req, res, next) => {
  console.log('Session ID:', req.session.id);
  next();
});

5. Структура базы данных

Убедитесь, что ваша таблица session настроена правильно. Например, она должна иметь уникальный индекс по sid (идентификатору сессии), чтобы гарантировать, что одна сессия не перезаписывает другую. Если уникальный индекс не установлен, это может объяснить, почему старые сессии перезаписываются. Попробуйте выполнить следующий SQL-запрос:

CREATE TABLE IF NOT EXISTS session (
  sid VARCHAR(255) NOT NULL PRIMARY KEY,
  sess JSON NOT NULL,
  expire TIMESTAMP NOT NULL
);

Заключение

Для решения вашей проблемы важно:

  1. Убедиться, что параметры resave и saveUninitialized установлены правильно.
  2. Проверить, что новая сессия создаётся при каждом входе пользователя.
  3. Включить логирование, чтобы отслеживать создание сессий.
  4. Проверить структуру таблицы сессий.

Применение этих решений должно помочь вам устранить проблему с тем, что в таблице сессий PostgreSQL хранится только одна строка независимо от количества пользователей.

Оцените материал
Добавить комментарий

Капча загружается...