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':
登录请求:
Feed请求:const response=await fetch('http://localhost:5000/user/login',{ method:'POST', body:JSON.stringify(details), headers: { 'Content-Type': 'application/json' }, credentials: 'include' // 新增 })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
相关产品推荐
相关产品推荐

