"为什么我的页面总被未登录用户访问?"——90%前端都踩过的鉴权大坑!
当你的管理后台被未授权用户直接访问,当用户刷新页面后登录状态丢失... 这些致命体验问题都源于路由鉴权缺失!今天用三个核心武器解决这个世纪难题:
import { Navigate, useLocation, useNavigate } from "react-router-dom";
🚨 鉴权失败的灾难现场
graph LR
A[用户访问/admin] --> B{已登录?}
B -->|否| C[空白页面]
B -->|是| D[正常展示]
结果: 未登录用户看到空白页/报错 → 用户流失率暴涨300%!
💡 解决方案:鉴权三剑客
1️⃣ Navigate组件:重定向终结者
// 当检测到未登录时,像子弹一样重定向到登录页
<Navigate to="/login" replace state={{ from: location }} />
特性:
replace: true替换历史记录(防止回退死循环)state携带来源路径(登录后精准返回)- 只能在组件渲染阶段使用
2️⃣ useLocation:路由信息侦察兵
const location = useLocation();
// 获取关键信息:
console.log(location.pathname) // "/admin/users"
console.log(location.search) // "?page=2"
console.log(location.state) // 来自Navigate的状态
核心作用:
捕获被拦截前的路由信息,实现 "从哪里中断,就回哪里去"
3️⃣ useNavigate:编程式导航指挥官
const navigate = useNavigate();
// 登录成功后执行精准导航
navigate(location.state?.from || "/home", { replace: true });
核爆级功能:
在异步操作(如登录请求)后执行导航,完美解决 "登录后回跳" 需求
⚡ 完整鉴权流程实战
Step 1:创建鉴权守卫组件
// src/components/AuthGuard.jsx
import { useLocation, Navigate } from "react-router-dom";
import { checkAuth } from "./auth";
export default ({ children }) => {
const location = useLocation();
return checkAuth() ?
children :
<Navigate to="/login" replace state={{ from: location }} />;
};
Step 2:路由配置注入守卫
// src/App.jsx
<Routes>
<Route path="/login" element={<LoginPage />} />
<Route
path="/dashboard"
element={
<AuthGuard>
<Dashboard />
</AuthGuard>
}
/>
<Route
path="/admin/*"
element={
<AuthGuard requireRole="admin">
<AdminLayout />
</AuthGuard>
}
/>
</Routes>
Step 3:登录页完成闭环
// src/pages/Login.jsx
import { useLocation, useNavigate } from "react-router-dom";
export default () => {
const location = useLocation();
const navigate = useNavigate();
const handleLogin = async () => {
await loginAPI(); // 登录API请求
// 关键!跳转回被拦截前的页面
navigate(location.state?.from || "/", { replace: true });
};
return (
<button onClick={handleLogin}>
登录后自动回到{location.state?.from || "首页"}
</button>
);
};
💥 进阶技巧:多维度鉴权方案
1. 角色权限控制
<AuthGuard
requireRole={["admin", "superadmin"]}
fallback={<NoPermissionPage />}
>
<AdminPanel />
</AuthGuard>
2. 权限过期处理
// 在AuthGuard中添加
useEffect(() => {
if (isTokenExpired()) {
logout(); // 清除过期待权
}
}, []);
3. 路由动画增强体验
<AuthGuard>
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
>
<Dashboard />
</motion.div>
</AuthGuard>
🚀 效果对比:鉴权方案进化史
| 方案 | 代码量 | 用户体验 | 安全性 |
|---|---|---|---|
| 裸奔无鉴权 | 0行 | ⭐ | 🔴 |
| 组件内粗暴跳转 | 30行 | ⭐⭐ | 🟡 |
| 三剑客方案 | 15行 | ⭐⭐⭐⭐⭐ | 🟢 |
💎 避坑指南:血泪总结
-
循环重定向陷阱
// 错误!在登录页也使用AuthGuard <Route path="/login" element={<AuthGuard><LoginPage /></AuthGuard>} />✅ 正确做法: 将登录页排除在守卫之外
-
state丢失问题
刷新页面时location.state会消失,解决方案:// 存储到sessionStorage state={{ from: location.pathname + location.search }} -
权限更新不及时
在全局添加监听:// 监听权限变化 useSubscribe(authStore, () => forceUpdate());
黄金法则:
路由鉴权不是限制,而是用户体验的保险丝!
用好三剑客,让非法访问归零,用户留存率提升200%!