实现路由守卫(JWT)—React篇

在 React 中,没有像 Vue 或 Angular 那样的内置路由守卫功能。但是,我们可以使用 React Router 或其他第三方库,结合一些自定义逻辑来实现类似的功能,接下来就让我们试试看吧。

JWT逻辑思维导图

结合导图,能更可观的了解整个流程,下面我们就直接上实操。

示例

以下是基于 React Router 实现路由守卫的基本示例:

假设:使用react-redux统一管理用户的状态

  1. 安装 React Router
csharp 复制代码
npm install react-router-dom react-redux
# 或者  
yarn add react-router-dom react-redux
  1. 定义一个外部处理高阶Layout:

创建一个自定义的 Layout 组件,该组件在渲染之前会检查某些条件(例如用户是否已登录)。如果条件不满足,则重定向到另一个页面(例如登录页)。

获取状态管理中的用户状态,判断是否存在Token,存在则拉取用户信息,并更新用户信息状态

typescript 复制代码
import { useSelector, useDispatch } from "react-redux";
export const Layout = (
  props: any
) => {
  const dispatch = useDispatch()
  const user = useSelector<any, { userInfo: UserInfo, token: string }>((state) => state.UserReduce)
   useEffect(() => {
    if (user.token) {

      getUserInfo<{ roles: string[], avatar: string, name: string }>()
        .then(res => {
          dispatch(setUserInfo(res.data))
        })
    }

  }, [user.token])

}

路由守卫逻辑:

  • 使用 useMemo Hook 来记忆(或缓存)根据路由和 token 决定的组件渲染结果。

  • component 变量存储了最终要渲染的组件或 null(表示需要重定向或不做任何操作)。

  • 路由守卫逻辑:

    • 如果 token 存在且当前路由是登录页('/login'),则使用 history.go(-1) 返回上一页。
    • 如果 token 不存在且当前路由不是登录页,则使用 window.location.replace 重定向到登录页,并带上当前路由作为查询参数。
    • 如果以上两种情况都不满足,则渲染 props.children(即传递给 Layout 组件的子组件)。
typescript 复制代码
export const Layout = (
  props: any
) => {
  const location = useLocation() 
  const dispatch = useDispatch() 
  const history = createBrowserHistory()
  const user = useSelector<any, { userInfo: UserInfo, token: string }>((state) => state.UserReduce) // redux数据
  
  useEffect(() => {
    if (user.token) {

      getUserInfo<{ roles: string[], avatar: string, name: string }>()
        .then(res => {
          dispatch(setUserInfo(res.data))
          
          if (res.code === 401) { // 清除token,并返回登录页
          
          }
        })
    }

  }, [user.token])

  const component = useMemo(() => { // 监听路由变化------------ 路由守卫
    
    const { pathname, search } = location
    const token = user.token

    if(token && pathname === '/login') {
      history.go(-1)
      return null
    }

    if(!token && pathname !== '/login') {
      window
        .location
        .replace(`/login?redirect=${pathname}${search ? search : ''}`)

      return null
    }

    return props.children
    
  }, [location.pathname])

  
  return component
}
  1. 定义一个路由管理组件RouteLink

定义 onEnter 函数

  • onEnter 是一个使用 useCallback Hook 定义的函数,它接收一个 Component 作为参数。
  • 这个函数返回一个新的 JSX 元素,该元素是一个 Layout 组件,Layout 组件内部包裹了传入的 Component
  • useCallback 的依赖项数组为空,因为onEnter不依赖于任何外部变量。
javascript 复制代码
/ 假设 ASSETS_MENUS 在组件外部已经定义好,并且是一个数组,每个元素都有 path 和 element 属性  
// const ASSETS_MENUS = [  
//   { path: '/', element: <HomePage /> },  
//   { path: '/about', element: <AboutPage /> },
 // { path: '/login', element: <Login /> }
//   // ... 其他路由配置  
// ];  

const RouterLink = () => {   
  const onEnter = React.useCallback((Component) => {  
    return <Layout><Component /></Layout>;  
  }, []); // 依赖项数组为空,因为onEnter不依赖于任何外部变量  
  
  return (  
    <div>  
      <BrowserRouter>  
        <Routes>  
          {ASSETS_MENUS.map((comp) => (  
            <Route  
              key={comp.path}  
              path={comp.path}  
              element={onEnter(comp.element)}  
            />  
          ))}  
        </Routes>  
      </BrowserRouter>  
    </div>  
  );  
};  
  1. APP入口中使用

直接使用就行了。

javascript 复制代码
const App = () => {  
  return (  
    <div>
        // 其他
        <RouterLink />
    </div>
  );  
};  

路由守卫只是前端的安全措施之一。仍然需要在后端实施适当的安全措施,以确保即使前端逻辑被绕过,敏感数据也不会被未经授权的用户访问。

相关推荐
GIS之路4 分钟前
GDAL 实现矢量裁剪
前端·python·信息可视化
是一个Bug8 分钟前
后端开发者视角的前端开发面试题清单(50道)
前端
Amumu1213810 分钟前
React面向组件编程
开发语言·前端·javascript
持续升级打怪中31 分钟前
Vue3 中虚拟滚动与分页加载的实现原理与实践
前端·性能优化
GIS之路35 分钟前
GDAL 实现矢量合并
前端
hxjhnct37 分钟前
React useContext的缺陷
前端·react.js·前端框架
冰暮流星1 小时前
javascript逻辑运算符
开发语言·javascript·ecmascript
前端 贾公子1 小时前
从入门到实践:前端 Monorepo 工程化实战(4)
前端
菩提小狗1 小时前
Sqlmap双击运行脚本,双击直接打开。
前端·笔记·安全·web安全
前端工作日常1 小时前
我学习到的AG-UI的概念
前端