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

Passport JS本地策略在React前端认证失败求助

Passport JS Local Strategy 前端认证失败排查

我用Passport JS Local Strategy实现用户认证功能,Postman里测试一切正常,但对接React前端后出现问题:调用/login接口成功后,访问/feed接口始终返回“Not Authenticated”,尽管MongoDB里已经存储了会话记录。


后端代码

index.js

import express from 'express';
import bodyParser from 'body-parser';
import mongoose from 'mongoose';
import cors from 'cors';
import * as dotenv from "dotenv";
import passport from "passport";
import session from "express-session";
import feedRoute from './routes/feed.routes.js';
import userRoute from './routes/users.routes.js';
import MongoStore from 'connect-mongo';

dotenv.config();
const app=express();
app.use(bodyParser.json());
app.use(cors());
app.use(session({
    secret: "secret",
    resave: false,
    saveUninitialized: false,
    store: MongoStore.create({ mongoUrl: process.env.MONGO_URI }),
}));
app.use(passport.initialize())
app.use(passport.session())

app.get('/',(req,res)=>{res.send("John Doe")})

app.use('/feed', feedRoute);
app.use('/user', userRoute);

const CONNECTION_URL = process.env.MONGO_URI;
const PORT = process.env.PORT || 5000;

mongoose.connect(CONNECTION_URL,{ useNewUrlParser: true,useUnifiedTopology: true})
    .then(()=>app.listen(PORT, ()=> console.log(`Server running on Port : ${PORT}`)))
    .catch((error)=>console.log(error.message));

user.routes.js

import express from "express";
import User from "../models/user.js";
import passport from "passport";
import initializingPassport from "../passportConfig.js";

initializingPassport(passport);

const router = express.Router();

// register api here that works

router.route('/login').post(passport.authenticate("local", { failureFlash: true }), (req, res)=> {
    res.status(200).send(JSON.stringify({message:"Logged in"}));
})

export default router;

feed.routes.js

import express from 'express';

import passport from "passport";
import initializingPassport, {isAuthenticated} from "../passportConfig.js";

const router = express.Router();
initializingPassport(passport)

router.route('/').get(isAuthenticated, (req, res) => {
    console.log(req.session)
    res.json({ message: 'Authenticated' });
});

export default router;

passportConfig.js

import {Strategy as LocalStrategy} from "passport-local";
import User from "./models/user.js";

export default function initializePassport(passport) {
  passport.use(
    new LocalStrategy({ usernameField: "email" }, async function (email, password, done) {
      try {
        const user = await User.findOne({ email: email });
        if (!user) {
          return done(null, false, { message: "Incorrect username" });
        }
        if (!(await user.comparePassword(password))) {
          return done(null, false, { message: "Incorrect password" });
        }
        return done(null, user);
      } catch (error) {
        return done(error);
      }
    })
  );

  passport.serializeUser((user, done) => {
    done(null, user.id)
  })

  passport.deserializeUser(async (id, done) => {
    try{
      const user = await User.findById(id)
      done(null, user);

    } catch(error) {
      done(error, false);
    }
  })
}

export function isAuthenticated(req, res, done) {
  if(req.user) return done();

  res.status(401).send(JSON.stringify({'message': "Not Authenticated"}))
}

前端代码

登录请求代码

const handleSubmit=async (e)=>{
    e.preventDefault()
    const response=await fetch('http://localhost:5000/user/login',{
      method:'POST',
      body:JSON.stringify(details),
      headers: {
        'Content-Type': 'application/json',
      },
      
    })
    const res= await response.json()
    console.log(res)
    if(res.message==='400'){
      seterr('Login failed')
      console.log(err)}
    else{
      seterr('')
      nav('/feed')
    }
  }

Feed组件请求代码

import React, {useState, useEffect} from 'react';
import { useNavigate } from 'react-router-dom';

export const Feed = () => {
  const nav = new useNavigate();

  useEffect(() => {
      const ftechData = async() => {
        const res = await fetch('http://localhost:5000/feed', {
          method: 'GET',
          headers: {
            'Content-Type': 'application/json',
          },
        })

        const data = await res.json();

        if(data.message!='Authenticated'){
          console.log(data.message)
          nav('/login')
        } 
      }
      ftechData()
  }, []);

  return (
    <div>
      <h1 className='header-text'>Feed</h1>
    </div>
  )
}

问题根源及修复方案

1. 跨域请求未携带会话凭证

前端跨域请求默认不会携带Cookie(会话标识),后端CORS配置和前端请求都需要开启凭证支持:

  • 后端修改CORS配置:
app.use(cors({
  origin: "http://localhost:3000", // 替换为你的React前端地址
  credentials: true // 允许跨域携带凭证
}));
  • 前端所有请求添加credentials: 'include':
    登录请求:
    const response=await fetch('http://localhost:5000/user/login',{
      method:'POST',
      body:JSON.stringify(details),
      headers: { 'Content-Type': 'application/json' },
      credentials: 'include' // 新增
    })
    
    Feed请求:
    const res = await fetch('http://localhost:5000/feed', {
      method: 'GET',
      headers: { 'Content-Type': 'application/json' },
      credentials: 'include' // 新增
    })
    

2. Session Cookie缺少跨域属性

会话Cookie需要配置跨域相关参数,确保前端能接收并在后续请求中携带:
修改session配置:

app.use(session({
    secret: "secret",
    resave: false,
    saveUninitialized: false,
    store: MongoStore.create({ mongoUrl: process.env.MONGO_URI }),
    cookie: {
      sameSite: process.env.NODE_ENV === 'production' ? 'none' : 'lax', // 生产环境用none,开发环境用lax
      secure: process.env.NODE_ENV === 'production', // 生产环境开启secure(仅HTTPS),开发环境设为false
      maxAge: 24 * 60 * 60 * 1000 // 可选,设置Cookie有效期1天
    }
}));

3. isAuthenticated中间件写法错误

当前中间件不符合Express规范,改用Passport内置的isAuthenticated()方法:
修改passportConfig.js中的isAuthenticated:

export function isAuthenticated(req, res, next) {
  if(req.isAuthenticated()) { // 使用Passport提供的校验方法
    return next();
  }
  res.status(401).json({'message': "Not Authenticated"});
}

4. 重复初始化Passport

user.routes.js和feed.routes.js中重复调用initializingPassport(passport),会导致策略重复注册。删除这两个文件中的初始化代码,只保留index.js中的一次初始化即可。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 00:25:39