Express+Passport.js后端在React客户端返回认证失败,浏览器正常
问题描述
搭建了集成Passport.js的Express后端,/check-auth接口在浏览器直接访问时返回authenticated: true,但通过React前端Axios发起请求时却返回authenticated: false,怀疑是req.isAuthenticated()的使用存在问题,相关代码如下:
Express后端代码
const express = require("express"); const mongoose = require("mongoose"); const cors = require("cors") require("dotenv").config() const session = require("express-session"); const MongoStore = require('connect-mongo'); const passport = require("passport") const LocalStrategy = require("passport-local").Strategy; const bcrypt = require("bcrypt"); const app = express() app.use(cors({ origin:'http://localhost:3000', credentials: true })); mongoose.connect(process.env.DATABASE_URI) .then(()=> console.log("connected to the Database") ) .catch(error => console.log(error)) app.use(session({ secret: 'thekey', resave: true, saveUninitialized: true, store:MongoStore.create({mongoUrl:process.env.DATABASE_URI}), cookie: { maxAge: 24 * 60 * 60 * 1000, // 1 day }, })); app.use(passport.initialize()); app.use(passport.session()); app.use(express.urlencoded({ extended: true })); app.use(express.json()) // 模型定义部分省略... // Passport配置 passport.serializeUser((user, done) => { done(null, user.id); }); passport.deserializeUser(async (id, done) => { try { user = await User.findById(id); if(!user) { return done(new Error('User not found')); } done(null, user) } catch (err) { done(err) } }); passport.use(new LocalStrategy( function(username, password, done) { User.findOne({ username: username }) .then(user => { if (!user) { return done(null, false, { message: 'Incorrect username.' }); } if (user.password !== password) { return done(null, false, { message: 'Incorrect password.' }); } return done(null, user); }) .catch(err => { return done(err); }); } )); // 接口定义部分省略... app.post('/signin', passport.authenticate('local'), (req, res) => { console.log('User:', req.user); res.json({ isAuthenticated: req.isAuthenticated(), user: req.user }); }); app.get('/check-auth', (req, res) => { if (req.isAuthenticated()) { return res.json({ authenticated: true, user: req.user }); } else { return res.json({ authenticated: false, user: null }); } }); app.listen(3400 , ()=> { console.log("port is running on port 3400") })
React前端代码
const HomePage = (props) => { const [courts , setCourts ] = useState([]) const navigate = useNavigate(); useEffect(()=>{ const grabCourts = async () =>{ const res = await axios.get(`http://localhost:3400/courts`) setCourts(res.data) } grabCourts() },[]) const [isAuth ,setIsAuth] = useContext(AuthContext) useEffect(() => { const checkAuth = async () => { try{ const res = await axios.get(`http://localhost:3400/check-auth`) .then((res)=>{ console.log(res) }) } catch(err){ console.log(`error : ${err}`) } } checkAuth() }, [] ) return( <div className="container" > <Top/> <h1 className="top-heading">Top Courts</h1> <div className="cards"> { courts.slice(0,3).map((court)=>( <div className="card" key="_id"> <h1> {court.name} </h1> <h2> {court.address} </h2> <div className="court-type"> <img src={bb} className="bb-image"></img> <p className="court-num">{court.courtCount} x</p> <Link to={`/courts/${court._id}`}> <button className="read-more">More Info</button> </Link> </div> </div> ))} </div> </div> ) } export default HomePage
问题分析与解决方案
不是req.isAuthenticated()的使用问题,核心原因是跨域请求时Axios未携带Session Cookie:Passport.js依赖Session Cookie识别已认证用户,浏览器直接访问会自动携带Cookie,但跨域AJAX请求默认不会发送Cookie,导致后端无法识别用户会话。
修复步骤
1. 前端Axios开启凭证携带
修改checkAuth函数,在请求中添加withCredentials: true:
const checkAuth = async () => { try{ const res = await axios.get(`http://localhost:3400/check-auth`, { withCredentials: true // 关键:携带Session Cookie }) .then((res)=>{ console.log(res) }) } catch(err){ console.log(`error : ${err}`) } }
如果多个请求都需要携带Cookie,可全局配置Axios:
import axios from 'axios'; axios.defaults.withCredentials = true;
2. 后端Session Cookie配置优化
调整Session的Cookie属性,确保跨域场景下能正常传递:
app.use(session({ secret: 'thekey', resave: false, // 建议改为false,减少不必要的会话更新 saveUninitialized: false, // 建议改为false,仅在会话有数据时存储 store:MongoStore.create({mongoUrl:process.env.DATABASE_URI}), cookie: { maxAge: 24 * 60 * 60 * 1000, // 1 day httpOnly: true, // 增强安全性,防止XSS攻击 sameSite: 'lax', // 允许跨域请求携带Cookie // 生产环境HTTPS下需开启: // secure: process.env.NODE_ENV === 'production' }, }));
3. 额外验证点
- 确认登录后浏览器已存储Session Cookie:在开发者工具的
Application -> Cookies中查看localhost:3400下的会话Cookie。 - 后端CORS配置已正确设置
credentials: true(当前配置无误)。
内容的提问来源于stack exchange,提问作者Paul Morgan
相关产品推荐
相关产品推荐

