我用 express 制作了一个简单的 api,并用 react 制作了一个简单的前端。当我通过 react 向 express /login 路径发送带有 axios 的登录请求时,我收到 302 错误。以前它是有效的,但我的护照会话没有持续存在,我读到 axios 默认情况下不发送凭据,所以当我将 axios.defaults.withCredentials 更改为 true 时它坏了,现在在提交登录表单时给我一个 302 错误
快递应用程序.js:
const express = require('express');
const { registerUser } = require('./routeFunctions')
const session = require('express-session')
const passport = require('passport');
const bcrypt = require('bcrypt')
const LocalStrategy = require('passport-local').Strategy
const { checkAuthenticated, getUserFromDBByUsername, getUserFromDB, getPokemon } = require('./helper')
const dotenv = require('dotenv').config
const bodyParser = require('body-parser')
const cors = require('cors')
const app = express()
const port = 5000
const secret = process.env.SECRET
const corsConfig = {
origin: true,
Credentials: true,
}
app.use(bodyParser.urlencoded())
app.use(express.text())
app.use(cors(corsConfig))
app.options('*', cors(corsConfig))
app.use(session({
secret: secret,
cookie: {maxAge: 60 * 60 * 1000, sameSite: 'none', httpOnly: true, secure: false},
saveUninitialized: false,
resave: false
}));
app.use(passport.initialize());
app.use(passport.session());
passport.serializeUser((user, done) => {
done(null, user.user_id)
})
passport.deserializeUser((id, done) => {
user = getUserFromDB(id, async (user) => {
if (!user) {
return done(null, false);
}
return done(null, user);
});
})
passport.use(new LocalStrategy( async (username, password, done) => {
getUserFromDBByUsername(username, async (user) => {
user = user[0]
try {
if (!user) {
return done(null, false)
}
const passwordMatched = await bcrypt.compare(password, user.password);
if (passwordMatched) {
console.log('password matched')
return done(null, user)
} else {
return done(null, false)
}
} catch(error) {
console.log(error)
}
})
})
);
app.get('/home', (req, res) => {
getPokemon((results) => {
res.json(results)
})
})
app.get('/', (req, res) => {
res.set({"Content-Type": "application/json"})
res.json({authorized: false})
})
app.get('/auth', (req, res) => {
console.log(req.session)
res.set({"Content-Type": "application/json"})
res.json({authorized: true})
})
app.post('/login', passport.authenticate('local', { failureRedirect: '/'}),
(req, res) => {
console.log(req.session)
res.redirect('/auth')
})
app.post('/register', registerUser)
app.listen(port, () => {
console.log(`app running on port ${port}`)
})
helper.js:
const mysql = require('mysql2');
const user = process.env.USER;
const pass = process.env.PASSWORD
const con = mysql.createConnection({
host: 'localhost',
database: 'pokemon_prototype_db',
user: user,
password: pass
});
const getPokemon = (callback) => {
const results = con.query(`
SELECT pokemon_users.is_caught,
pokemon.pokemon_id,
pokemon.pokemon_name,
pokemon.region,
pokemon.type
FROM pokemon_users
INNER JOIN pokemon On pokemon_users.pokemon_id = pokemon.pokemon_id
where user_id = ?
`, 42, (error, results) => {
if (error) {
throw (error)
} else {
return callback(results)
}
})
}
const checkAuthenticated = (req, res, next) => {
if (req.isAuthenticated()) {
return next()
}
console.log(req.isAuthenticated())
res.redirect('/')
};
const getUserFromDB = (id, callback) => {
const results = con.query('SELECT * FROM users WHERE user_id = ?', [id], (error, results) => {
if (error) {
throw (error)
}
return callback(results)
});
return callback(results)
};
const getUserFromDBByUsername = (username, callback) => {
con.query('SELECT * FROM users WHERE username = ?', username, (err, results) => {
if (err) {
throw(err)
}
return callback(results)
});
};
module.exports = {
checkAuthenticated,
getUserFromDB,
getUserFromDBByUsername,
getPokemon
}
反应 App.js:
import { useState, useEffect } from "react";
import { useNavigate, Route, Routes, BrowserRouter, Navigate, Link } from 'react-router-dom'
const { LoginForm } = require("./login.jsx")
const { Register } = require("./register.jsx")
const { Home } = require('./Home.jsx')
const App = () => {
return (
<>
<BrowserRouter>
<Routes>
<Route exact path="/login" element={<LoginForm/>}/>
<Route exact path="/register" element={<Register/>}/>
<Route exact path="/home" element={<Home/>}/>
</Routes>
</BrowserRouter>
</>
)
}
export default App`
反应登录.jsx:
import axios from 'axios';
import { react, useState, useEffect } from 'react'
import { useNavigate, Link } from 'react-router-dom';
const LoginForm = () => {
const navigate = useNavigate()
const [username, setUsername] = useState('');
const [password, setPassword] = useState('');
const loginUser = async (e) => {
e.preventDefault();
const body = {
username: username,
password: password
}
axios.defaults.baseURL = ''
axios.defaults.withCredentials = true
const loggedIn = await axios.post("http://localhost:5000/login", body, {
headers: {
"Content-Type": "application/x-www-form-urlencoded"
}
})
.then((response) => {return response.data})
.catch(err => {
throw (err)
});
console.log(loggedIn)
if (loggedIn.authorized === true) {
return navigate("/home")
} else {
console.log('this isnt working')
}
}
return (
<>
<div>
<form onSubmit={loginUser}>
<input value={username} onChange={(e) => setUsername(e.target.value)} type='text'></input><br/>
<input value={password} onChange={(e) => setPassword(e.target.value)} type='password'></input><br/>
<button type="submit">Login</button><br/>
</form>
<Link to="/register">register</Link>
</div>
</>
)
}
export {LoginForm}
它在没有将 axios.defaults.withCredentials 设置为 true 的情况下工作,但是我无法实现对我的端点的授权,因为会话中的 passport 元素在没有设置为 true 的情况下不会持续存在。与邮递员一起测试时,后端也按预期工作