MERN栈注册场景下路由文件中Express Session无法更新保存
问题1:CORS配置不支持跨域传递Cookie
前后端分离场景下默认跨域请求不会携带身份凭证Cookie,导致两次请求无法关联同一个Session,修改app.js的CORS配置:
// 替换原来的app.use(cors()) app.use(cors({ // 填你的前端实际访问地址,不能用*通配符 origin: "http://localhost:3000", // 允许跨域发送Cookie credentials: true }))
同时前端发送请求时必须开启凭证携带:
- Axios配置:
axios.defaults.withCredentials = true - Fetch配置:
fetch(url, { credentials: 'include' })
问题2:Session配置参数错误
你将过期时间直接写在了Session配置根节点,实际expires属于cookie的配置项,同时开发环境下如果用HTTP协议,要关闭Cookie的安全限制,修改app.js的Session配置:
app.use( session({ secret: process.env.SECRET, resave: false, // 没有修改时不用重存,减少性能消耗 saveUninitialized: false, // 未初始化的Session不用存储,减少无效存储 proxy: true, cookie: { // 1小时过期,用maxAge更方便不用手动计算时间 maxAge: 3600000, // 开发环境用HTTP的话设为false,生产环境HTTPS设为true secure: process.env.NODE_ENV === 'production', // 防止前端JS读取Cookie,降低XSS风险 httpOnly: true } }) );
问题3:数据库查询是异步操作,当前逻辑执行顺序混乱
你现在写的两个User.findOne是异步回调,代码不会等待查询结果返回就会直接执行后续的Session存储、邮件发送逻辑,就算邮箱/用户名已存在也会走后续流程,需要改成async/await同步执行逻辑:
修改routes/auth.js的注册路由:
// 给路由函数加async关键字 router.post("/register", async (req, res) => { const { username, email, password } = req.body; //check email matches the pattern if (!validateEmail(email)) { return res.json({ status: "error", message: "Email is not valid", }); } // 用await等待查询结果 const emailExist = await User.findOne({ email: email }); if (emailExist) { return res.json({ status: "error", message: "Email already exists, please sign in", }); } const usernameExist = await User.findOne({ username: username }); if (usernameExist) { return res.json({ status: "error", message: "Username already exists, please choose another one", }); } // 剩余原有校验逻辑不变... // 生成验证码逻辑不变... var charSet = new securePin.CharSet(); charSet.addLowerCaseAlpha().addUpperCaseAlpha().addNumeric().randomize(); const code = securePin.generateStringSync(6, charSet); // save info in session req.session.username = username; req.session.email = email; req.session.password = password; req.session.code = code; // session.save是异步操作,要等存储完成再发邮件返回响应 req.session.save((err) => { if (err) { return res.json({ status: "error", message: "Session存储失败,请重试" }) } // 发送邮件逻辑放在save回调里 const mailOptions = { from: process.env.EMAIL_ADDRESS, to: email, subject: "no reply- book tracker confirmation", text: `Your verification code is: ${code}.`, }; transporter.sendMail(mailOptions, (err, info) => { if (err) { return res.json({ status: "error", message: err.message.toString(), }); } return res.json({ status: "success", message: "Email sent", }); }); }) });
额外安全提示
不要明文存储密码,建议用bcrypt对密码加密后再存入Session和数据库,避免密码泄露风险。
内容的提问来源于stack exchange,提问作者Darshan B
相关产品推荐
相关产品推荐

