Node.js+MongoDB实现用户名密码认证及Cookie存储问题求助
问题背景
基于Node.js Express框架和MongoDB开发登录页面,注册功能正常,但登录功能无法正确完成用户认证,需要实现基于MongoDB的用户名/密码验证,并完善用户Cookie存储逻辑。
原代码核心问题
- 登录接口仅查询用户存在性,未验证密码正确性,无论匹配结果如何都直接跳转
- 用户密码明文存储,存在安全风险
- Cookie的
secure属性在HTTP开发环境下无法生效,导致Cookie无法设置 - 数据库连接未添加错误处理,注册时异步保存操作未等待完成就跳转
修复后的完整代码
//------------modules used-------------// const express = require("express"); const path = require("path"); const helmet = require("helmet"); const cookieparser = require("cookie-parser"); const mongoose = require("mongoose"); const bcrypt = require("bcrypt"); // 新增:用于密码哈希 //------------modules used-------------// const app = express(); app.use(helmet()); app.use(cookieparser()); app.use(express.json()); app.use(express.urlencoded({ extended: false })); //-------------------mongodb-----------------// // 新增数据库连接错误处理 mongoose.connect("mongodb://localhost:27017/loginDB", { useNewUrlParser: true }) .then(() => console.log("MongoDB连接成功")) .catch(err => console.error("MongoDB连接失败:", err)); const userSchema = new mongoose.Schema({ email: { type: String, unique: true, required: true }, // 新增唯一性约束 pass: { type: String, required: true }, }); // 新增:保存前自动哈希密码 userSchema.pre("save", async function(next) { if (!this.isModified("pass")) return next(); this.pass = await bcrypt.hash(this.pass, 10); next(); }); const User = mongoose.model("User", userSchema); //-------------------mongodb-----------------// app.set("view engine", "ejs"); app.set("views", path.join(__dirname, "views")); app.get("/", (req, res) => { let username = req.cookies.username; if (username) { return res.render("mainpage", { username }); } else { res.redirect("/login"); } }); app.get("/mainpage", (req, res) => { let username = req.cookies.username; if (username) { return res.render("mainpage", { username }); } else { res.redirect("/login"); } }); app.get("/register", (req, res) => { return res.render("signup"); }); app.get("/login", (req, res) => { let bad_auth = req.query.msg ? true : false; if (bad_auth) { return res.render("login", { error: "Invalid username or password" }); } else { return res.render("login"); } }); // 修复登录接口:正确验证用户名和密码 app.post("/login", async (req, res) => { try { const { username, password } = req.body; // 查找用户,用findOne而非find(find返回数组) const user = await User.findOne({ email: username }); if (!user) { return res.redirect("/login?msg=fail"); } // 验证密码哈希 const isPasswordValid = await bcrypt.compare(password, user.pass); if (!isPasswordValid) { return res.redirect("/login?msg=fail"); } // 根据环境设置secure属性:生产环境HTTPS设为true,开发环境设为false const isProduction = process.env.NODE_ENV === "production"; res.cookie("username", username, { maxAge: 30 * 24 * 60 * 60 * 1000, secure: isProduction, httpOnly: true, sameSite: 'lax' }); res.redirect("/mainpage"); } catch (err) { console.error("登录错误:", err); res.redirect("/login?msg=fail"); } }); // 修复注册接口:等待保存完成再跳转,处理重复注册 app.post("/register", async (req, res) => { try { const { given_username, given_password } = req.body; // 检查用户是否已存在 const existingUser = await User.findOne({ email: given_username }); if (existingUser) { // 可添加提示用户已存在的逻辑 return res.redirect("/register"); } const newUser = new User({ email: given_username, pass: given_password, }); await newUser.save(); // 等待保存完成 const isProduction = process.env.NODE_ENV === "production"; res.cookie("username", given_username, { maxAge: 30 * 24 * 60 * 60 * 1000, secure: isProduction, httpOnly: true, sameSite: 'lax' }); res.redirect("/"); } catch (err) { console.error("注册错误:", err); res.redirect("/register"); } }); app.get("/logout", (req, res) => { res.clearCookie("username"); return res.redirect("/login"); }); app.listen(3000, () => console.log(`服务器启动在端口3000`));
关键修改说明
- 密码安全:引入
bcrypt库,在用户保存前自动哈希密码,登录时验证哈希值,避免明文存储风险 - 登录认证逻辑:使用
User.findOne查找单个用户,对比密码哈希,只有验证通过才设置Cookie跳转 - Cookie适配:根据运行环境设置
secure属性,开发环境(HTTP)设为false确保Cookie正常生效 - 异步操作处理:注册和登录接口改用
async/await处理MongoDB异步操作,确保数据操作完成后再响应 - 数据库优化:添加用户邮箱唯一性约束,避免重复注册;新增数据库连接错误处理,便于排查问题
- 错误处理:添加全局异常捕获,登录/注册失败时统一跳转至对应页面
内容的提问来源于stack exchange,提问作者Arsh Meharwal
相关产品推荐
相关产品推荐

