在现代前端开发中,路由守卫(Route Guards)是实现页面权限控制的核心工具,它允许开发者在用户访问特定路由时,根据条件(如登录状态、角色权限等)动态决定是否允许访问。
本文将结合代码案例,深入解析路由守卫的实现原理和使用方法。
一、路由守卫概念简介
1.1 路由守卫的定义
路由守卫是一种在路由切换时触发的逻辑机制,它通过拦截导航行为,根据预设规则决定是否允许用户进入目标页面。
路由守卫常见的应用场景有:
- 身份验证:用户未登录时跳转到登录页。
- 权限控制:根据用户角色限制访问某些页面。
- 数据预加载:在进入页面前加载必要的数据。
- 操作拦截:防止用户未保存表单时直接离开页面。
1.2 为什么需要路由守卫?
- 路由守卫可以防止未授权用户访问一些敏感页面(如支付页面)。
- 避免用户因权限不足导致的页面空白或错误。
- 将权限逻辑集中管理,降低业务组件复杂度。
- 支持动态权限配置,适应复杂业务场景。
二、路由守卫的使用
2.1 核心逻辑:ProtectRoute
组件
// ProtectRoute.jsx
import { Navigate, useLocation } from 'react-router-dom'
const ProtectRoute = ({ children }) => {
const { pathname } = useLocation()
const isLogin = localStorage.getItem('isLogin') === 'true'
if (!isLogin) {
return <Navigate to="/login" state={{ from: pathname }} />
}
return children
}
export default ProtectRoute
上面的代码是一个 React 路由守卫组件 ,用于实现路由权限控制,只有用户登录后,才能访问受保护的页面,否则跳转到登录页,并记录用户原本想访问的路径。
代码分析:
-
useLocation
:
用于获取当前路由的路径信息(pathname
),记录用户访问的目标页面,在登录成功后跳转回原路径。 -
localStorage
:
用于模拟登录状态,而localStorage.getItem('isLogin') === 'true'
用来判断用户是否登录。 -
Navigate
组件:
React Router v6 提供的导航组件,用于程序化跳转,Navigate
会强制跳转到指定路由,并传递参数(如from: pathname
)。 -
children
传递:
通过props.children
将受保护的页面组件传递给ProtectRoute
, 这种方式类似于 Vue 的插槽(slot),允许动态插入内容。
2.2.2 路由配置与守卫绑定
// App.jsx
import { lazy, Suspense } from 'react'
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'
import Navigation from './components/Navigation'
import ProtectRoute from './pages/ProtectRoute'
import Pay from './pages/Pay'
import Login from './pages/Login'
const Home = lazy(() => import('./pages/Home'))
const About = lazy(() => import('./pages/About'))
const NotFound = lazy(() => import('./pages/NotFound'))
function App() {
return (
<Router>
<Navigation />
<Suspense fallback={<div>正在加载中...</div>}>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
{/* 需要鉴权的页面 */}
<Route
path="/pay"
element={
<ProtectRoute>
<Pay />
</ProtectRoute>
}
/>
<Route path="*" element={<NotFound />} />
<Route path="login" element={<Login />} />
</Routes>
</Suspense>
</Router>
)
}
export default App
以上的代码定义了整个应用的路由结构,使用了懒加载和路由守卫机制,实现对 /pay
页面的访问控制。
代码分析:
-
懒加载(Lazy Loading):
使用lazy
和Suspense
动态加载页面组件,优化首屏性能,fallback={<div>正在加载中...</div>}
在组件加载时显示提示。 -
路由守卫绑定:
第26行代码中,将ProtectRoute
包裹在/pay
路由的element
中,想要访问/pay
,就要先访问ProtectRoute
,这样可以实现对该路由的保护。
2.2.3 登录页面的实现
// Login.jsx
import { useState } from 'react'
import { useNavigate, useLocation } from 'react-router-dom'
const Login = () => {
const [username, setUsername] = useState('')
const [password, setPassword] = useState('')
const navigate = useNavigate()
const location = useLocation()
const handleSubmit = (event) => {
event.preventDefault()
if (username === 'admin' && password === '123456') {
localStorage.setItem('isLogin', 'true')
navigate(location?.state?.from || '/')
} else {
alert('用户名或密码错误')
}
}
return (
<form onSubmit={handleSubmit}>
<h1>登录页面</h1>
<input
type="text"
placeholder="请输入用户名"
value={username}
onChange={(e) => setUsername(e.target.value)}
/>
<input
type="password"
placeholder="请输入密码"
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
<button type='submit'>确定</button>
</form>
)
}
export default Login
上面的代码实现了一个简单的登录页面,用于验证用户身份,并在登录成功后跳转回用户原本想访问的页面或首页。
代码分析:
-
用
useNavigate
替代history.push
的 API,用于编程式导航,navigate(location?.state?.from || '/')
实现登录成功后跳转回原路径或首页。 -
location.state.from
:
用于记录用户访问受保护页面时的路径,登录成功后跳转回原路径,其中,location.state
是 React Router 提供的参数传递方式。
四、总结
功能 | 说明 |
---|---|
路由守卫作用 | 控制页面访问权限,提升应用安全性 |
React 实现方式 | 自定义组件包裹 children ,结合 Navigate 实现跳转 |
权限扩展方式 | 可通过传入 requiredRole 实现角色权限控制 |
登录状态管理 | 可使用 localStorage 或 context/redux 进行统一状态管理 |
路由守卫是前端权限控制的重要手段,能够在用户访问页面前进行身份或权限校验,保障应用安全,通过合理使用路由守卫,不仅可以提升用户体验,还能使权限逻辑更清晰、更易维护。