登录凭证匹配数据库但React登录表单无法跳转至首页问题排查
问题
开发了一个React登录表单,注册功能正常,但登录时出现异常:
- 输入不匹配凭证时,控制台报错
Login.js:44 POST http://localhost:3001/login 401 (Unauthorized) - 输入匹配凭证时,401错误消失,但控制台输出自定义的"login failed"日志,无法跳转至首页
已确认能连接数据库并校验凭证,修改URL端点无效,附上前端登录表单代码和后端服务器代码。
原因分析
前端路由跳转逻辑错误:
自定义的withRouter高阶组件传递给Login组件的是router对象(包含navigate方法),但代码中判断的是props.history是否存在——实际上props中根本没有history属性,导致即使登录成功(response.status===200),条件也永远不成立,直接进入else分支输出"login failed"。同时react-router-dom v6已废弃history.push,改用navigate方法。后端CORS配置缺失凭证支持:
登录使用了session和passport,需要前端请求携带cookie凭证,但默认的cors()配置不允许跨域携带凭证,可能导致session无法正常建立,影响后续登录状态验证。
解决方案
前端代码修改
方案1:直接使用useNavigate(推荐,无需自定义withRouter)
删除自定义的withRouter高阶组件,在Login组件中直接调用useNavigate:
import React from "react"; import Input from "./Input"; import { useForm } from "react-hook-form"; import { yupResolver } from "@hookform/resolvers/yup"; import * as yup from "yup"; import { useNavigate } from "react-router-dom"; const schema = yup.object({ username: yup.string().required("Username is a required field"), password: yup.string().min(6, "Password must be at least 6 characters"), }); function Login(props) { const navigate = useNavigate(); const { handleSubmit, register, formState: { errors }, } = useForm({ resolver: yupResolver(schema), }); const formSubmit = (data) => { fetch("http://localhost:3001/login", { method: "POST", body: JSON.stringify({username: data.username, password: data.password}), headers: { "Content-Type": "application/json" }, credentials: "include", }) .then(async (response) => { if (response.ok) { const result = await response.json(); console.log(result.message); navigate("/"); } else { const error = await response.json(); console.log("login failed:", error.message); } }) .catch((error) => { console.error("Error:", error); }); }; return ( <div className="sign-up"> <h1>Log in</h1> <p>Lorem ipsum dolor, sit amet consectetur</p> <form onSubmit={handleSubmit(formSubmit)}> <Input id="username" label="Username" type="text" placeholder="Enter Username" register={{ ...register("username") }} errorMessage={errors.username?.message} /> <Input id="password" label="Password" type="password" placeholder="Enter Password" register={{ ...register("password") }} errorMessage={errors.password?.message} /> <button>Log in</button> </form> <button className="button-link" onClick={() => props.onFormSwitch("signup")}> Don't have an account? Register here. </button> </div> ); } export default Login;
方案2:修复自定义withRouter的props传递
如果坚持使用withRouter,需将navigate直接作为props传递:
// 修改withRouter函数 function withRouter(Component) { function ComponentWithRouterProp(props) { let location = useLocation(); let navigate = useNavigate(); let params = useParams(); return ( <Component {...props} navigate={navigate} router={{ location, navigate, params }} /> ); } return ComponentWithRouterProp; } // 修改formSubmit中的跳转逻辑 const formSubmit = (data) => { fetch("http://localhost:3001/login", { method: "POST", body: JSON.stringify({username: data.username, password: data.password}), headers: { "Content-Type": "application/json" }, credentials: "include", }) .then(async (response) => { if (response.ok) { props.navigate("/"); } else { console.log("login failed"); } }) .catch((error) => { console.error("Error:", error); }); };
后端代码修改
修复CORS配置,支持跨域凭证
替换默认的cors配置,指定允许的前端origin并开启凭证支持:
// 替换原来的app.use(cors()); app.use(cors({ origin: "http://localhost:3000", // 你的前端项目运行端口,通常为3000 credentials: true }));
额外建议:密码加密存储
当前明文存储密码存在安全风险,建议使用bcrypt哈希加密:
- 安装依赖:
npm install bcrypt - 注册时加密密码:
const bcrypt = require("bcrypt"); const saltRounds = 10; // 在注册路由中 bcrypt.hash(password, saltRounds, (err, hash) => { if (err) throw err; const newUser = new Signup({ username, password: hash }); newUser.save(); });
- 登录时验证哈希:
// 修改passport的local策略 passport.use( 'local', new LocalStrategy(function (username, password, done) { Signup.findOne({ username: username }, function (err, user) { if (err) { return done(err); } if (!user) { return done(null, false); } bcrypt.compare(password, user.password, (err, result) => { if (err) return done(err); result ? done(null, user) : done(null, false); }); }); }) );
内容的提问来源于stack exchange,提问作者user19102549
相关产品推荐
相关产品推荐

