我对以下代码有一个问题,它快把我逼疯了.
简而言之,我想做的是:
-登录成功后,将会话存储中保存的JWT令牌状态保存.
-在某个状态下保存Boolean isTokenValid.
-通过/api/validateToken终结点的GET请求判断令牌是否有效,并相应地设置isTokenValid.
-如果令牌有效(isTokenValid=true)-->;显示仪表板
-如果令牌无效(is TokenValid=False)--&>显示错误页面
-
App.jsx
import './styles/Reset.css'; import './styles/App.css'; import 'bootstrap/dist/css/bootstrap.min.css'; import React from 'react'; import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'; import axios from 'axios'; import Home from './components/Home'; import Header from './components/Header'; import Footer from './components/Footer'; import Login from './components/Login'; import Signup from './components/Signup'; import Dashboard from './components/Dashboard'; import FailedAuth from './components/FailedAuth'; function App() { const [token, setToken] = React.useState(sessionStorage.getItem('token')); const [isTokenValid, setIsTokenValid] = React.useState(false); const [loading, setLoading] = React.useState(true); async function validateToken() { try { const response = await axios.get('http://localhost:5000/api/validateToken', { headers: { 'Authorization': `Bearer ${token}` } }); if (response.status === 200) { setIsTokenValid(true); } else { setIsTokenValid(false); } } catch (error) { setIsTokenValid(false); } finally { setLoading(false); } } React.useEffect(() => { async function fetchData() { if (token) { await validateToken(); } } fetchData(); }); if (loading) { return ( <div className="loading"> <div className="spinner-border text-primary" role="status"> <span className="visually-hidden">Loading...</span> </div> </div> ); } return ( <Router> <Routes> <Route path="/login/*" element={ <> <Header type="auth" /> <Login /> </> } /> <Route path="/signup/*" element={ <> <Header type="auth" /> <Signup /> </> } /> <Route path="/*" element={ <> <Header type="home" /> <Home /> <Footer /> </> } /> <Route path="/dashboard/*" element={ <> {isTokenValid ? <Dashboard /> : <FailedAuth />} </> } /> </Routes> </Router> ); } export default App;
-
Server.js
app.get('/api/validateToken', passport.authenticate('jwt', { session: false }), (req, res) => { try { res.status(200).json({ message: 'Token is valid' }); } catch (error) { res.status(500).json({ error: error.message }); } });
服务器完美地处理了身份验证,并且正确地分配了JWT令牌.
我的问题恰恰在于以isTokenValid为条件的路由的呈现.
当用户登录时,它将呈现到仪表板上,即使令牌有效,它也会立即显示<;FailedAuth/>;,但如果我刷新页面,它将显示<;Dashboard/>;,正如它应该显示的那样.
令牌过期后,始终会显示<;FailedAuth/>;,所以这没有问题,它会做它应该做的事情.
我认为这是一个同步问题,但我不确定(我还是个新手,这是我的第一个项目).
有谁能帮帮我吗?这样当我发现自己面临同样的情况时,我知道将来该怎么做.
这是我设置sessionStorage时的部分代码:
import React, { useState } from 'react';
import axios from 'axios';
import { useNavigate } from 'react-router-dom';
import TipsAndUpdatesTwoToneIcon from '@mui/icons-material/TipsAndUpdatesTwoTone';
import Alert from '@mui/material/Alert';
function AuthForm(props) {
const navigate = useNavigate();
// Stato che contiene i dati del form
const [formData, setFormData] = useState({
email: '',
username: '',
password: '',
confirmPassword: '',
});
const [error, setError] = useState('');
const [show, setShow] = useState(true);
function handleCloseClick() {
setShow(false);
}
// Funzione che gestisce l'invio del form
async function handleSubmit(event) {
event.preventDefault();
setTimeout(() => {
setShow(true);
}, 1000);
try {
let response;
if (props.type === 'login') {
response = await axios.post('http://localhost:5000/api/login', formData);
sessionStorage.setItem('token', response.data.token);
navigate('/dashboard');
} else if (props.type === 'signup') {
response = await axios.post('http://localhost:5000/api/signup', formData);
}
console.log(response.data);
} catch (error) {
console.log(error.response.data);
if (error.response.data.error) {
setError(error.response.data.error);
} else {
setError(error.response.data.message);
}
}
// Resetta il form dopo l'invio
setFormData({
email: '',
username: '',
password: '',
confirmPassword: '',
});
};
// Funzione che gestisce i cambiamenti dei campi del form
function handleChange(event) {
setFormData({ ...formData, [event.target.name]: event.target.value });
};
// Renderizza il form
return (
<>
{error && show && (
<Alert onClose={() => {handleCloseClick()}} severity="error" className='mb-4'>{error}</Alert>
)}
<div className="d-flex justify-content-center">
<h1 className='icon-yellow'>
{props.type === 'login' ? 'Log In' : 'Sign Up'}{' '}
<TipsAndUpdatesTwoToneIcon className='icon-yellow' style={{ fontSize: '3.5rem' }}/>
</h1>
</div>
<form className="auth-form" onSubmit={handleSubmit}>
<div className="form-group">
<label htmlFor="email">Email</label>
<input className="form-control" type="email" name="email" value={formData.email} onChange={handleChange} />
</div>
{props.type === 'signup' && (
<div className="form-group">
<label htmlFor="username">Username</label>
<input className="form-control" type="text" name="username" value={formData.username} onChange={handleChange} />
</div>
)}
<div className="form-group">
<label htmlFor="password">Password</label>
<input className="form-control" type="password" name="password" value={formData.password} onChange={handleChange} />
</div>
{props.type === 'signup' && (
<div className="form-group">
<label htmlFor="confirmPassword">Confirm Password</label>
<input className="form-control" type="password" name="confirmPassword" value={formData.confirmPassword} onChange={handleChange} />
</div>
)}
<button className="auth-button" type="submit">
{props.type === 'login' ? 'Login' : 'Sign Up'}
</button>
</form>
</>
);
}
export default AuthForm;