部署EC2后Express-session无法在请求头设置Cookie的问题
将Node.js后端部署到EC2后,服务地址变为http://52.xx.xx.xx:8080,出现前端请求无法在请求头中携带Cookie的问题,导致SSO验证失败。
流程说明
- 用户在前端(
localhost:5173)点击“登录”,重定向到SSO服务器(http://localhost:8080/login?serviceURL=localhost:5173)完成登录操作; - 用户输入邮箱密码后,Passport将SSO服务器的session(sessionId)存入数据库Sessions表,并设置包含该sessionId的Cookie;
- 客户端携带SSO token及Cookie向SSO服务器发起请求,服务器通过Cookie中的sessionId查询数据库,调用
deserializeUser填充req.user。
问题现象
部署到EC2后,浏览器中connect.sid Cookie的域为52.xx.xx.xx,前端调用http://52.xx.xx.xx:8080/verify-token接口时,请求头无法携带Cookie,导致req.user为undefined,接口返回404错误“Not match sso token”。本地localhost:8080环境下功能正常。
已尝试设置Cookie的sameSite为"lax",但无效。
相关配置代码
config.session配置
app.use( session({ secret: "keyboard cat", store: myStore, resave: false, // 我们支持touch方法,根据express-session文档应设为false proxy: true, // 若在node之外使用SSL saveUninitialized: false, checkExpirationInterval: 15 * 60 * 1000, // 清理过期会话的时间间隔(毫秒) expiration: 500 * 1000, cookie: { httpOnly: true, maxAge: 24 * 60 * 60 * 1000, secure: false, path: "/", }, }) ); // 正常继续执行 myStore.sync(); app.use(passport.authenticate("session")); passport.serializeUser(function (user, cb) { process.nextTick(function () { // cb(null, { id: user.id, username: user.username }); cb(null, user); }); }); passport.deserializeUser(function (user, cb) { process.nextTick(function () { return cb(null, user); }); }); };
loginController.js配置
const getLoginPage = (req, res) => { const { serviceURL } = req.query; return res.render("login.ejs", { redirectURL: serviceURL, }); }; const verifySSOToken = async (req, res) => { try { const { ssoToken } = req.body; console.log("check code from req.user", req.user); if (req.user && req.user.code && req.user.code === ssoToken) { const refreshToken = uuidv4(); //更新用户refresh token await AuthService.updateRefreshToken(req.user.email, refreshToken); let payload = { user_id: req.user.user_id, roleWithPermission: req.user.roleWithPermission, first_name: req.user.first_name, last_name: req.user.last_name, phone: req.user.phone, address: req.user.address, email: req.user.email, }; let token = createToken(payload); //设置cookies res.cookie("refresh_token", refreshToken, { httpOnly: true, maxAge: 60 * 60 * 24 * 1000, secure: false, path: "/", }); res.cookie("access_token", token, { httpOnly: true, maxAge: 60 * 60 * 1000, secure: false, path: "/", }); const resData = { user_id: req.user.user_id, access_token: token, refresh_token: refreshToken, email: req.user.email, first_name: req.user.first_name, last_name: req.user.last_name, phone: req.user.phone, address: req.user.address, roleWithPermission: req.user.roleWithPermission, }; //销毁会话 req.session.destroy(function (err) { req.logout(); }); return new OK({ EM: "Verify token successfully", DT: resData, }).send(res); } else { throw new UnauthorizedResponse({ EM: "Not match sso token", DT: "", }); } } catch (error) { console.log(error); if (error instanceof ErrorResponse) { return error.send(res); } return new ErrorResponse({ EM: "Error verifying SSO token from server", }).send(res); } };
passportController.js配置
import passport from "passport"; import LocalStrategy from "passport-local"; import AuthService from "../services/auth.service"; const configPassport = () => { passport.use( new LocalStrategy({}, async (username, password, done) => { try { const rawData = { valueLogin: username, password: password, }; const user = await AuthService.login(rawData); console.log("Check user passport Controller", user); if (user && +user.EC === 1) { return done(null, user.DT); } else { return done(null, false, { message: user.EM }); } } catch (error) { console.error("Login error:", error); return done(error); } }) ); }; const handleLogout = (req, res) => { // req.logout(); // res.redirect("/login"); req.session.destroy(function (err) { req.logout(); res.redirect("/"); }); }; export { configPassport, handleLogout };
CORS配置
require("dotenv").config(); const allowedOrigins = [ "*", process.env.REACT_PATH, process.env.REACT_PATH_SSO, //localhost:5173 process.env.SERVICE_PATH, process.env.DOCKER_SSO_PATH, process.env.DOCKER_SSO_PATH + "/api/v1", "http://" + process.env.HOST_NAME + ":" + process.env.PORT, //localhost:8080 process.env.PUBLIC_SSO_PATH, //http://52.xx.xx.xx:8080 process.env.PUBLIC_SSO_PATH + "/api/v1", process.env.PRIVATE_SSO_PATH, process.env.PRIVATE_SSO_PATH + "/api/v1", process.env.SERVICE_PATH, ].filter(Boolean); module.exports = allowedOrigins;
import allowedOrigins from "./allowedOrigin"; const corsOption = { origin: (origin, callback) => { if (allowedOrigins.indexOf(origin) !== -1 || !origin) { callback(null, true); } else { callback(new Error("Not allowed by CORS")); } }, methods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"], allowedHeaders: [ "Content-Type", "Authorization", "X-Requested-With", "Access-Control-Allow-Credentials", ], exposedHeaders: [ "Set-Cookie", "Access-Control-Allow-Credentials", "set-cookie", ], credentials: true, optionsSuccessStatus: 200, }; export default corsOption;
import allowedOrigins from "../configs/CORS/allowedOrigin"; const credentials = (req, res, next) => { const origin = req.headers.origin; if (allowedOrigins.includes(origin)) { res.header("Access-Control-Allow-Credentials", true); } next(); }; export default credentials;
相关截图


内容的提问来源于stack exchange,提问作者Thuận Phát
相关产品推荐
相关产品推荐

