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

React客户端使用Passport认证异常:上传请求无法通过isLoggedIn中间件

MERN栈会话认证问题:前端上传请求无法通过isLoggedIn中间件

我正在开发基于MERN栈的应用,使用Passport、passport-local和passport-local-mongoose实现会话式认证。前端包含登录页、注册页和上传路由,后端采用Node.js与MongoDB。登录时服务器返回成功,但上传请求无法通过isLoggedIn中间件;然而使用Hoppscotch工具时,登录及上传请求均能正常执行。


相关代码

登录页组件

import axios from "axios";
import React, { useState } from "react";

import "./login.css";

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

  const onSubmit = (e) => {
    e.preventDefault();
    const obj = { username: username, password: password };
    
    axios
      .post("http://localhost:4000/api/login", obj)
      .then((res) => {
        console.log("login response: ", res);
        if(res.status === 200) {
          alert("Logged in!!!");
        // window.location.href = "/";
        }
      })
      .catch((e) => {
        alert("error");
        console.log(e);
      });
  };
  return (
    <div className="cont">
      <form className="input" onSubmit={onSubmit}>
        <label className="label" htmlFor="username">Username:</label>
        <input
          className="input"
          type="text"
          id="username"
          onChange={(e) => setUsername(e.target.value)}
        />
        <label className="label" htmlFor="password">Password:</label>
        <input
          className="input"
          type="password"
          id="password"
          onChange={(e) => setPassword(e.target.value)}
        />
        <button className="button" type="submit" value="submit">
          Submit
        </button>
      </form>
    </div>
  );
};

export default Login;

上传页组件

import React, { useState } from "react";
import axios from "axios";

const Home = () => {
  const [file, setFile] = useState();

  const onSubmit = (e) => {
    e.preventDefault();
    const data = new FormData();
    data.append("file", file);

    axios
      .post("http://localhost:4000/api/upload/resume", data, {
        withCredentials: true,
        headers: { "Content-Type": "multipart/form-data" },
      })
      .then((file) => {
        console.log("worked ", file);
      })
      .catch((e) => {
        console.log(e);
      });
  };

  return (    
    <form onSubmit={onSubmit}>    
      <p>Submit your resume pdf here ( Resume pdf should be 12 Mb or less )</p>    
      <input     
        type="file"    
        id="pdf-file"    
        onChange={(e) => setFile(e.target.files[0])}   
      />   
      <button type="submit">Upload</button>   
    </form>   
  );
};

export default Home;

登录路由(后端)

router.post("/login", (req, res, next) => {
  passport.authenticate("local", (err, user, info) => {
    if (err) throw err;
    if (!user) res.send("No User Exists");
    else {
      req.logIn(user, (err) => {
        if (err) throw err;
        res.send("Successfully Authenticated");
        console.log(req.user);
      });
    }
  })(req, res, next);
});

isLoggedIn中间件(后端)

const isLoggedIn = (req, res, next) => {
  console.log(req);
  if (req.isAuthenticated()) {
    console.log("authenticated");
    return next();
  }
  console.log("not authenticated");
  throw new Error("User not authenticated");
};

module.exports = isLoggedIn;

问题原因及解决办法

核心问题是登录请求未携带凭证,导致会话Cookie未被前端保存,后续上传请求的身份验证自然失效。Hoppscotch默认自动保存并发送Cookie,因此测试正常。

具体修复步骤:

  1. 给登录请求添加凭证配置
    修改登录页的axios请求,加入withCredentials: true,确保会话Cookie被前端保存:

    axios
      .post("http://localhost:4000/api/login", obj, { withCredentials: true })
      .then((res) => {
        console.log("login response: ", res);
        if(res.status === 200) {
          alert("Logged in!!!");
        }
      })
      .catch((e) => {
        alert("error");
        console.log(e);
      });
    
  2. 后端配置允许跨域凭证
    如果使用cors包,需明确开启允许携带凭证:

    const cors = require('cors');
    app.use(cors({
      origin: "http://localhost:3000", // 替换为你的前端地址
      credentials: true
    }));
    
  3. 移除上传请求的手动Content-Type设置
    axios会自动为FormData生成包含boundary的正确multipart/form-data头,手动设置会导致验证错误:

    axios
      .post("http://localhost:4000/api/upload/resume", data, {
        withCredentials: true
        // 删除此行:headers: { "Content-Type": "multipart/form-data" },
      })
    
  4. 检查会话中间件配置
    确保express-session的Cookie参数设置合理,适配开发/生产环境:

    const session = require('express-session');
    app.use(session({
      secret: 'your-secure-secret-key',
      resave: false,
      saveUninitialized: false,
      cookie: {
        httpOnly: true,
        sameSite: 'lax', // HTTPS跨域环境可设为'none'
        secure: process.env.NODE_ENV === 'production'
      }
    }));
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 13:51:30