You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Express+PassportJS会话异常:Profile请求重复创建新会话

问题描述

后端使用Express(运行在5500端口),通过PassportJS实现用户认证,用session追踪登录状态;前端采用React框架(运行在3000端口)。

目前调用/api/login的POST请求可成功登录用户,返回200状态码并创建包含Passport用户对象的会话,跳转至Profile页面后,调用/api/profile的GET请求获取用户数据时,每次都会创建新会话,覆盖登录时生成的会话,导致认证状态丢失,提示用户未认证。


后端代码

server.js

const express = require("express");
const MongoStore = require("connect-mongo");
const indexRouter = require("./routes/index");
const app = express();
const cors = require("cors");
const bodyparser = require("body-parser");
const mongoose = require("mongoose");
const dotenv = require("dotenv");
const passport = require("./Authentication/passportConfig");
const session = require("express-session");
const cookieParser = require("cookie-parser");
dotenv.config({ path: "../app/Private/.env" });
let port = process.env.PORT;

app.use(bodyparser.json());
app.use(bodyparser.urlencoded({ extended: true }));
app.use(
  cors({
    origin: "http://localhost:3000",
    methods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
    credentials: true,
  })
);

app.use(cookieParser("secret"));
app.use(
  session({
    secret: "secret",
    store: MongoStore.create({ mongoUrl: process.env.ADMIN_URI }),
    resave: false,
    saveUninitialized: false,
    cookie: { maxAge: 30 * 24 * 60 * 60 * 1000, httpOnly: true },
  })
);
app.use(passport.initialize());
app.use(passport.session());

//Database connection process
mongoose
  .connect(process.env.ADMIN_URI, {
    useNewUrlParser: true,
    useUnifiedTopology: true,
  })
  .then(() => console.log("connected to database"))
  .catch(console.error);

//Route creation
app.use("/api", indexRouter);

app.listen(port, () => console.log("Server connected and running: " + port));

路由代码(indexRouter)

const express = require("express");
const router = express.Router();
const passport = require("../Authentication/passportConfig");
const dotenv = require("dotenv");
dotenv.config({ path: "../app/Private/.env" });
const nodemailer = require("nodemailer");
const User = require("../model/user");
const hash = require("../Authentication/passwordHash");
const validator = require("node-email-validation");
const Appointment = require("../model/appointment");

router.post("/login", passport.authenticate("local"), (req, res) => {
  var time = new Date(Date.now());
  console.log(
    "Session ID before @ /login route: " +
      time.toLocaleTimeString() +
      ": " +
      req.sessionID
  );
  if (req.user) {
    console.log("Session ID after @ /login route: " + req.sessionID);
    console.log("User is logged in: " + req.user.username);
    console.log("User is Authenticated: " + req.isAuthenticated());
    res.status(200).json({ message: "Login successful" });
  } else {
    res.send(400).json({ message: "User not found" });
  }
});

router.get("/profile", function (req, res) {
  var time = new Date(Date.now());
  console.log(
    "Session ID @ /profile route: " +
      time.toLocaleTimeString() +
      ": " +
      req.sessionID
  );
  if (req.isAuthenticated()) {
    console.log(req.isAuthenticated());
    console.log("user: " + req.user.username);
    return res.status(200).json(req.user);
    num = num + 1;
  } else {
    console.log("else Statement");
    return res.status(302).json({ message: "User not found" });
  }
});

会话日志输出

Session ID before @ /login route: 5:41:07 PM: 8Z1RebDKynOESWoQ5ecA3EecOojmthL9
Session ID after @ /login route: 8Z1RebDKynOESWoQ5ecA3EecOojmthL9
User is logged in: alex@s3v.us
User is Authenticated: true
Session ID @ /profile route: 5:41:09 PM: -peiT761fG_ZY9gLgWFpqeUE6hTZmRQV
else Statement
Session ID @ /profile route: 5:41:09 PM: kgXFngZMamCqh4mapynMQQN7cgL9Er-1
else Statement
Session ID @ /profile route: 5:41:09 PM: zCZTtlsK-g0MSvo9j5ZbAAs35vaXtsnO
else Statement
Session ID @ /profile route: 5:41:09 PM: Oq8J-s08m66P5JuuTO1RI5ZIy8oOeXRD
else Statement

前端代码

Login页面调用代码

const config = {
    headers: {
      "Access-Control-Allow-Origin": "http://localhost:3000",
      "Access-Control-Allow-Methods": "GET,PUT,POST,DELETE,PATCH,OPTIONS",
      "Access-Control-Allow-Credentials": "true",
    },
  };

const isLoggedIn = () => {
    axios
      .get("http://localhost:5500/api/profile", config)
      .then((res) => {
        console.log("Is user logged in status: " + res.status);
        console.log(res.data);
        if (res.status === 200) {
          window.location.href = "/MyProfile";
        }
      })
      .catch((err) => {
        console.log("err" + err);
      });
  };

  /*
    on Submit function for the login page
    */
  const onSubmitLogIn = (e) => {
    e.preventDefault();
    const user = {
      username: username.toString().toLowerCase(),
      password: password,
    };
    axios
      .post("http://localhost:5500/api/login", user, config)
      .then((res) => {
        console.log(res.data);
        if (res.status === 200) {
          setSuccessMessage(true);
          setTimeout(() => {
            window.location.href = "/MyProfile";
          }, 2000);
        }
      })
      .catch((err) => {
        setErrormessage(true);
      });
  };

Profile页面请求代码

useEffect(() => {
    fetchUserData();
  }, []);

  const fetchUserData = () => {
    axios
      .get("http://localhost:5500/api/profile", config)
      .then((res) => {
        console.log("res: " + res);
        console.log("User: " + res.data);
        setUserData(res.data);
      })
      .catch((err) => {
        console.log(err);
        console.log(err.response);
      });
  };

问题根源与修复方案

问题根源

前端跨域请求时未携带会话Cookie,后端无法识别已登录的会话,因此每次请求/api/profile都会创建新会话ID,导致认证状态丢失。

修复步骤

  1. 修正前端axios请求配置
    你当前的config设置了后端才需要返回的Access-Control-*响应头,属于无效配置。需要添加withCredentials: true,让axios在跨域请求时自动携带Cookie:

    const config = {
      withCredentials: true,
    };
    
  2. 优化后端session的Cookie配置
    在session配置中添加sameSite: "lax",确保跨域场景下Cookie能正常传递(本地开发环境用lax即可,生产环境如果是HTTPS可以用none并配合secure: true):

    app.use(
      session({
        secret: "secret",
        store: MongoStore.create({ mongoUrl: process.env.ADMIN_URI }),
        resave: false,
        saveUninitialized: false,
        cookie: { 
          maxAge: 30 * 24 * 60 * 60 * 1000, 
          httpOnly: true,
          sameSite: "lax" // 新增配置
        },
      })
    );
    
  3. 验证效果
    登录成功后,检查浏览器的Cookie存储(开发者工具 -> Application -> Cookies),确认存在connect.sid Cookie;访问Profile页面时,后端日志的req.sessionID应与登录时一致,此时req.isAuthenticated()会返回true,可正常获取用户数据。


内容的提问来源于stack exchange,提问作者Vibhore Sagar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 23:30:17