如何使用Passport.js、Axios和react-router-dom v6保护前端路由
实现方案
第一步:调整后端接口适配前后端分离场景
你当前使用的successRedirect/failureRedirect是服务端渲染场景的配置,前后端分离场景下需要改为返回JSON响应,同时新增鉴权状态查询接口:
var passport = require("passport"); router.post( "/login", passport.authenticate("local", { session: true, // 开启session存储 failWithError: true // 鉴权失败返回错误 }), (req, res) => { // 鉴权成功返回成功信息 res.json({ code: 0, message: "登录成功", user: req.user }) }, (err, req, res, next) => { // 鉴权失败返回错误 res.status(401).json({ code: 1, message: "用户名或密码错误" }) } ); // 新增鉴权状态查询接口 router.get('/check-auth', (req, res) => { if (req.isAuthenticated()) { return res.json({ isLoggedIn: true, user: req.user }) } res.status(401).json({ isLoggedIn: false }) }) module.exports = router;
第二步:前端封装私有路由守卫组件
react-router-dom v6 基于组件化实现路由保护,我们封装通用的私有路由组件,用于包裹所有需要鉴权的页面,新建components/PrivateRoute.js:
import { useState, useEffect } from 'react' import { Navigate } from 'react-router-dom' import instance from '../loginAPI.js' // 引入你封装好的带withCredentials的axios实例 const PrivateRoute = ({ children }) => { const [isAuth, setIsAuth] = useState(null) const [loading, setLoading] = useState(true) useEffect(() => { const checkAuth = async () => { try { await instance.get('/check-auth') setIsAuth(true) } catch (err) { setIsAuth(false) } finally { setLoading(false) } } checkAuth() }, []) if (loading) return <div>加载中...</div> // 可替换为你的自定义加载组件 return isAuth ? children : <Navigate to="/login" replace /> } export default PrivateRoute
第三步:修改路由配置应用鉴权规则
把需要保护的dashboard路由用PrivateRoute组件包裹即可:
import Login from "./pages/Login"; import Dashboard from "./pages/Dashboard"; import PrivateRoute from "./components/PrivateRoute"; import { BrowserRouter as Router, Routes, Route } from "react-router-dom"; function App() { return ( <div> <Router> <Routes> <Route exact path="/" element={<Login />} /> <Route path="/login" element={<Login />} /> {/* 受保护路由,只有登录后可以访问 */} <Route path="/dashboard" element={ <PrivateRoute> <Dashboard /> </PrivateRoute> } /> </Routes> </Router> </div> ); } export default App;
注意事项
后端CORS配置需要满足两个要求:
Access-Control-Allow-Credentials设为trueAccess-Control-Allow-Origin不能设置为通配符*,需要明确填写前端的访问地址(比如http://localhost:3000)
可选优化
如果想避免每次切换路由都发起鉴权查询请求,可以通过React Context、Zustand等全局状态管理方案缓存登录状态,登录成功后更新全局状态,路由守卫优先读取全局状态,不存在时再发起接口查询。
内容的提问来源于stack exchange,提问作者Tayne
相关产品推荐
相关产品推荐

