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

MERN Stack登录功能异常求助:输入错误密码仍可登录

问题:MERN Stack登录功能异常——错误密码仍能成功登录

我发现我的MERN Stack登录功能不符合预期:即使输入错误密码仍能成功登录。我已使用bcrypt.compare进行密码校验,校验不匹配时控制台会输出错误信息,但无法阻止登录流程。以下是相关代码:

路由代码

router.post("/login", async (req, res) => {
  const { username, password } = req.body;
  const foundOne = await User.findOne({ username });
  if (!foundOne) {
    return res.json({ message: "user does not exist" });
  }

  const isMatch = await bcrypt.compare(password, foundOne.password);
  if (!isMatch) {
    return res.json({ message: "password incorrect" });
  }

  const JWToken = jwt.sign({ id: foundOne._id }, secret);
  res.json({ JWToken, userID: foundOne._id });
});

Mongoose模型代码

const mongoose = require("mongoose");
const { Schema } = mongoose;

const userSchema = new Schema({
  username: {
    type: String,
    require: true,
    uniqle: true,
  },
  password: {
    type: String,
    require: true,
  },
  savedReceipes:[{type:mongoose.Schema.Types.ObjectId, ref: "recipes"}]
});

module.exports = mongoose.model("User", userSchema);

React登录页面代码

import React from "react";
import { useState } from "react";
import { useCookies } from "react-cookie";
import axios from "axios";
import { useNavigate } from "react-router-dom";

const Login = () => {
  const [username, setUsername] = useState("");
  const [password, setPassword] = useState("");

  const [_, setCookies] = useCookies("Jordan_token");
  const navigate = useNavigate();

  const handleLogin = async (event) => {
    event.preventDefault();
    try {
      const result = await axios({
        method: "post",
        url: "http://localhost:3001/user/login",
        data: { username, password },
        headers: {
          // "Content-Type": "multipart/data-form, charset=UTF-8",
          "Content-Type": "application/json; charset=UTF-8",
        },
      });
      console.log(result);

      setCookies("Jordan_token", result.data.JWToken);
      window.localStorage.setItem("userID", result.data.userID);
      // window.location.pathname="/"

      alert("Login success, now being redirected to Homg Page");
      navigate("/");
    } catch (err) {
      console.log(err.name);
      console.log(err.message);
    }
  };
  return (
    <div className="Login">
      <form>
        <h2>Login</h2>
        <div className="formDetail">
          <label htmlFor="username">Username:</label>
          <input
            type="text"
            id="username"
            value={username}
            onChange={(event) => setUsername(event.target.value)}
          />
        </div>
        <div className="formDetail">
          <label htmlFor="password">Password:</label>
          <input
            type="password"
            id="password"
            value={password}
            onChange={(event) => setPassword(event.target.value)}
            autoComplete="on"
          />
        </div>
        <div className="buttonDetail">
          <button onClick={handleLogin}>Login</button>
        </div>
      </form>
    </div>
  );
};

export default Login;

解决方案

核心问题在于后端错误返回未设置正确的HTTP状态码,导致前端axios不会触发catch逻辑,直接执行登录成功流程。同时前端也未对返回结果做错误判断,具体修正步骤如下:

1. 修正后端路由代码:返回错误状态码

当用户不存在或密码不匹配时,应返回401 Unauthorized状态码,而非默认的200成功状态码,这样axios会将其识别为错误并进入catch块:

router.post("/login", async (req, res) => {
  const { username, password } = req.body;
  const foundOne = await User.findOne({ username });
  if (!foundOne) {
    // 返回401状态码+错误信息
    return res.status(401).json({ message: "user does not exist" });
  }

  const isMatch = await bcrypt.compare(password, foundOne.password);
  if (!isMatch) {
    // 返回401状态码+错误信息
    return res.status(401).json({ message: "password incorrect" });
  }

  const JWToken = jwt.sign({ id: foundOne._id }, secret);
  res.json({ JWToken, userID: foundOne._id });
});

2. 前端代码:增加结果判断(可选但更严谨)

即使后端返回正确状态码,也可以在try块中先检查返回结果是否包含错误信息,避免意外执行登录成功逻辑:

const handleLogin = async (event) => {
  event.preventDefault();
  try {
    const result = await axios({
      method: "post",
      url: "http://localhost:3001/user/login",
      data: { username, password },
      headers: {
        "Content-Type": "application/json; charset=UTF-8",
      },
    });
    // 检查是否存在错误信息
    if (result.data.message) {
      alert(result.data.message);
      return;
    }

    setCookies("Jordan_token", result.data.JWToken);
    window.localStorage.setItem("userID", result.data.userID);
    alert("Login success, now being redirected to Home Page");
    navigate("/");
  } catch (err) {
    // 捕获后端返回的错误信息
    alert(err.response?.data?.message || "Login failed");
    console.log(err.name);
    console.log(err.message);
  }
};

3. 修正Mongoose模型的拼写错误(非当前问题核心,但需修复)

模型中存在两处拼写错误,可能导致后续数据验证问题:

  • require → required
  • uniqle → unique
  • savedReceipes → savedRecipes(拼写规范优化)

修正后的模型代码:

const mongoose = require("mongoose");
const { Schema } = mongoose;

const userSchema = new Schema({
  username: {
    type: String,
    required: true,
    unique: true,
  },
  password: {
    type: String,
    required: true,
  },
  savedRecipes:[{type:mongoose.Schema.Types.ObjectId, ref: "recipes"}]
});

module.exports = mongoose.model("User", userSchema);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 23:27:23