Express+React中Passport-Local认证重定向遇CORS错误,Google-OAuth正常
在Express与React项目里,使用Passport-Google-OAuth20策略完成认证后可以正常重定向到前端,但使用Passport-Local本地认证策略时,重定向操作会触发CORS错误。
后端代码
import { config } from "dotenv" import express,{Request,Response} from "express" import mongoose, {ConnectOptions, Error} from "mongoose"; import DeckModal from './models/deck'; import cors from "cors" import session from "express-session"; import passport from "passport"; import User from "./models/user"; import bcrypt from "bcryptjs" import { UserDetails } from "./types/UserDetails"; import passportLocal from "passport-local" const LocalStrategy=passportLocal.Strategy const MongoDBStore = require('connect-mongodb-session')(session); const GoogleStrategy =require("passport-google-oauth20") config() let PORT:number=5000 const app = express() app.use(express.json()) const store = new MongoDBStore({ uri: process.env.MONGO_URI!, collection: 'mysessions' }); store.on('error', function(error:Error) { console.log(error); }); app.use(cors({ origin:"http://localhost:5173" ,credentials:true})) app.set('trust proxy', 1) // 创建session app.use(session({ secret:process.env.SESSION_SECRET!, resave:true, saveUninitialized:true, store:store, // cookie:{ // httpOnly:true, //HttpOnly Cookie 可防止客户端脚本访问cookie数据 // sameSite:"none", // 前后端跨域时需设置sameSite:none以共享cookie // secure:true, // 仅允许HTTPS请求 // maxAge: 1000 * 60 * 60 * 24 * 7 // } })) app.use(passport.initialize()) app.use(passport.session()) // Local认证策略 passport.use(new LocalStrategy( {usernameField:"email"}, function(username, password, done) { User.findOne({ email: username }, function (err:Error, user:UserDetails) { if (err) { return done(err); } // 发生错误时返回错误信息 if (!user) { return done(null, false); } // 未找到用户时返回null和false bcrypt.compare(password,user.password!,(err,result)=>{ if(err) throw err if(result===true){ return done(null,user) } else{ return done(null,false) } }) }); } )); // Google认证策略 passport.use( new GoogleStrategy( { callbackURL: "/auth/google/callback", clientID: process.env.CLIENT_ID, clientSecret: process.env.CLIENT_SECRET, }, async (accessToken:any, refreshToken:any, profile:any, done:any) => { const userInfo:UserDetails={ email:profile.emails[0].value, profile_picture:profile.photos[0].value, username:profile.displayName } try{ const user= await User.findOne({ email: profile.emails[0].value }) if(!user){ const newUser= new User(userInfo) await newUser.save() return done(null,newUser) } return done(null,user) } catch(err){ return done(null,false,err) } } ) ); passport.serializeUser((user:any,done)=>{ return done(null,user._id) }) passport.deserializeUser((id:string,done)=>{ User.findById(id,(err:Error,doc:any)=>{ const userInfo={ username:doc.username, email:doc.email, profile_picture:doc.profile_picture, } return done(null,userInfo) }) }) // 连接MongoDB数据库 mongoose.connect(process.env.MONGO_URI!,{ useUnifiedTopology: true, useNewUrlParser: true } as ConnectOptions ) .then(()=>{ console.log("Connected to mongodb successfully"); // 数据库连接成功后启动服务 app.listen(process.env.PORT || PORT,()=>{ console.log("server is running on port "+PORT) }) }) .catch((err:Error)=>{console.log(err)}); // Google认证路由 app.get('/auth/google', passport.authenticate('google', { scope: ['profile','email'] })); app.get('/auth/google/callback', passport.authenticate('google', { failureRedirect: "http://localhost:5173/login", failureMessage: true,successRedirect:"http://localhost:5173/auth/success"})); app.get("/getuser",(req,res)=>{ if(req.user){ res.json(req.user) // Passport的deserializeUser会自动将用户信息附加到req.user } else{ res.json(null) } }) app.post('/auth/logout', function(req, res, next) { req.logout(function(err) { if (err) { return next(err); } res.send('done'); }); }); // 本地认证路由 app.post("/signup",async(req:Request,res:Response)=>{ const {username,email,password}=req?.body if(!username || !password || !email){ res.send("请提供用户名、邮箱和密码") return } try{ const user:UserDetails | null=await User.findOne({username}) if(!user){ const hashedPassword=await bcrypt.hash(password,10) const newUser= new User({ username, email, password:hashedPassword }) await newUser.save() res.send("注册成功") } else{ res.send("用户已存在") } } catch(error){ console.log(error) } }) app.post('/login', passport.authenticate('local'), (req, res) => { if(req.user){ res.redirect("http://localhost:5173/auth/success") } else{ res.status(200).json({success:false}); } } );
尝试过的修改
我曾尝试直接在passport.authenticate中配置successRedirect,但依然出现相同错误:
app.post('/login', passport.authenticate('local',{successRedirect:"http://localhost:5173/auth/success"}));
错误信息
Access to XMLHttpRequest at 'http://localhost:5173/' (redirected from 'http://localhost:5000/login') from origin 'http://localhost:5173' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.
前端请求代码
本地策略登录
const handleLogin = async (e:FormEvent<HTMLFormElement>) => { e.preventDefault() const data = { email, password }; axios.post("http://localhost:5000/login",data,{withCredentials:true}) }
Google策略登录
const handleGoogleLogin = async () => { window.open("http://localhost:5000/auth/google","_self") }
内容的提问来源于stack exchange,提问作者Max Vhanamane

