🔑 React路由鉴权终极指南:三剑客(Navigate+useLocation+useNavigate)实现无缝登录重定向

244 阅读2分钟

"为什么我的页面总被未登录用户访问?"——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行⭐⭐⭐⭐⭐🟢

💎 避坑指南:血泪总结

  1. 循环重定向陷阱

    // 错误!在登录页也使用AuthGuard
    <Route path="/login" element={<AuthGuard><LoginPage /></AuthGuard>} />
    

    ✅ 正确做法: 将登录页排除在守卫之外

  2. state丢失问题
    刷新页面时location.state会消失,解决方案:

    // 存储到sessionStorage
    state={{ from: location.pathname + location.search }}
    
  3. 权限更新不及时
    在全局添加监听:

    // 监听权限变化
    useSubscribe(authStore, () => forceUpdate());
    

黄金法则:
路由鉴权不是限制,而是用户体验的保险丝
用好三剑客,让非法访问归零,用户留存率提升200%!