如何用React和Node.js实现Http-only Cookie-JWT认证?
一、React端用户认证流程实现
Http-only Cookie由浏览器自动管理,React端不用手动存储token,核心处理好请求的Cookie携带、前端状态同步和受保护路由即可:
1. 登录请求处理
登录时直接调用后端登录接口,关键要在请求里加credentials: 'include',让浏览器自动保存并携带Cookie(跨域场景必须加,同源场景也建议加上):
// React登录组件示例 const Login = () => { const [username, setUsername] = useState(''); const [password, setPassword] = useState(''); const { setUser } = useAuth(); // 假设用全局Context管理用户状态 const navigate = useNavigate(); const handleLogin = async (e) => { e.preventDefault(); try { const res = await fetch('http://localhost:5000/api/login', { method: 'POST', credentials: 'include', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ username, password }) }); const data = await res.json(); if (res.ok) { // 登录成功,把后端返回的用户信息存入前端状态 setUser(data.user); navigate('/dashboard'); } else { alert(data.message || '登录失败'); } } catch (err) { console.error('登录请求出错:', err); alert('网络异常,请稍后重试'); } }; return ( <form onSubmit={handleLogin}> <input type="text" value={username} onChange={(e) => setUsername(e.target.value)} placeholder="用户名" required /> <input type="password" value={password} onChange={(e) => setPassword(e.target.value)} placeholder="密码" required /> <button type="submit">登录</button> </form> ); };
2. 页面刷新时恢复登录状态
页面刷新后前端状态会丢失,需要调用后端的验证接口,通过Cookie中的JWT获取当前用户信息,恢复前端状态:
// 全局状态初始化(比如在App.js或AuthContext中) useEffect(() => { const checkAuthStatus = async () => { try { const res = await fetch('http://localhost:5000/api/verify', { credentials: 'include' }); if (res.ok) { const user = await res.json(); setUser(user); } else { // 未登录或token过期,清空前端状态 setUser(null); } } catch (err) { console.error('认证状态检查失败:', err); setUser(null); } }; checkAuthStatus(); }, []);
3. 实现受保护路由
用React Router包裹需要登录才能访问的页面,判断前端用户状态是否存在:
// 受保护路由组件 const ProtectedRoute = ({ children }) => { const { user } = useAuth(); return user ? children : <Navigate to="/login" />; }; // 在路由配置中使用 <Routes> <Route path="/login" element={<Login />} /> <Route path="/dashboard" element={ <ProtectedRoute> <Dashboard /> </ProtectedRoute> } /> <Route path="/profile" element={ <ProtectedRoute> <UserProfile /> </ProtectedRoute> } /> </Routes>
二、Express端JWT验证中间件复用
完全可以沿用你之前EJS项目的验证中间件逻辑,只需要调整几个细节:
1. 核心验证逻辑不变
中间件从Cookie中取出JWT,验证有效性后把用户信息挂载到req.user上,示例:
// Express JWT验证中间件 const jwt = require('jsonwebtoken'); const authenticateToken = (req, res, next) => { // 从Cookie中获取token(对应你登录时设置的Cookie名) const token = req.cookies.jwt; if (!token) { return res.sendStatus(401); // 未携带token,返回未授权 } jwt.verify(token, process.env.JWT_SECRET, (err, user) => { if (err) { return res.sendStatus(403); // token无效或过期,返回禁止访问 } req.user = user; next(); // 验证通过,继续执行后续路由 }); };
2. 挂载到需要认证的路由
把中间件加到需要登录才能访问的路由上,比如验证接口和业务接口:
// 验证用户状态的接口,给React端恢复状态用 app.get('/api/verify', authenticateToken, (req, res) => { // 返回用户信息(注意不要返回敏感数据) res.json({ id: req.user.id, username: req.user.username, role: req.user.role }); }); // 受保护的业务接口示例 app.get('/api/dashboard/data', authenticateToken, (req, res) => { // 根据req.user获取对应的数据 res.json({ data: '仅登录用户可见的数据' }); });
3. 跨域与Cookie配置注意
如果React和Express跨域部署,必须配置CORS允许携带Cookie:
const cors = require('cors'); app.use(cors({ origin: 'http://localhost:3000', // 你的React项目域名/端口 credentials: true // 允许请求携带Cookie }));
同时登录时设置Cookie的属性,确保安全且兼容:
// 登录控制器中设置Cookie的代码 res.cookie('jwt', generatedToken, { httpOnly: true, // 禁止JS读取,防XSS maxAge: 24 * 60 * 60 * 1000, // 1天过期 sameSite: process.env.NODE_ENV === 'production' ? 'strict' : 'lax', // 生产环境用strict更安全 secure: process.env.NODE_ENV === 'production' // 生产环境开启,仅HTTPS传输 });
内容的提问来源于stack exchange,提问作者Emiya
相关产品推荐
相关产品推荐

