傻瓜式配置!react 路由权限、动态菜单方案 - react-router-auth-plus

5,172 阅读2分钟

2022-12-07 更新: 此文章不适用于 react-router 6.4+ 了,建议直接移步 react-router-auth-plus github 查看使用文档或源码 example 文件夹例子。

在 react 中做路由权限管理,一直是比较麻烦的事,不像 vue 中有进入路由前拦截的功能。在摸鱼时间撸了一个傻瓜式配置的路由权限 library (基于 react-router v6)。
react-router v6 文档地址
react-router-auth-plus github 地址

如何使用

1. 配置路由

import { AuthRouterObject } from "react-router-auth-plus";

const routers: AuthRouterObject[] = [
  { path: "/", element: <Navigate to="/home" replace /> },
  { path: "/login", element: <Login /> },
  {
    element: <Layout />,
    children: [
      { path: "/home", element: <Home />, auth: ["admin"] },
      { path: "/setting", element: <Setting /> },
      {
        path: "/application",
        element: <Application />,
        auth: ["application"],
      },
    ],
  },
  { path: "*", element: <NotFound /> },
];

2. 在应用的最外层渲染路由

这里我使用 swr 来模拟获取当前用户的权限,两秒后返回。

// App.tsx
import { useAuthRouters } from "react-router-auth-plus";

const fetcher = async (url: string): Promise<string[]> =>
  await new Promise((resolve) => {
    setTimeout(() => {
      resolve(["admin"]);
    }, 2000);
  });
  
function App() {
  const { data: auth, isValidating } = useSWR("/api/user", fetcher, {
    revalidateOnFocus: false,
  });

  return useAuthRouters({
    // 当前用户的权限,string[]
    auth: auth || [],
    routers,
    // 跳转到没权限的路由时,用户自定义显示。这里我显示 403 页面。
    noAuthElement: (router) => <NotAuth />,
    // 用户权限还没请求到时,渲染 loading
    render: (element) => (isValidating ? element : <Loading />),
  });
}

或你可以使用 jsx 的方式来配置

import { AuthRoute, createAuthRoutesFromChildren } from "react-router-auth-plus";

useAuthRouters({
    auth: auth || [],
    noAuthElement: (router) => <NotAuth />,
    render: (element) => (isValidating ? element : <Loading />),
    routers: createAuthRoutesFromChildren(
      <Routes>
        <AuthRoute path="/" element={<Navigate to="/home" replace />} />
        <AuthRoute path="/login" element={<Login />} />
        <AuthRoute element={<Layout />}>
          <AuthRoute path="/home" element={<Home />} auth={["admin"]} />
          <AuthRoute path="/setting" element={<Setting />} />
          <AuthRoute
            path="/application"
            element={<Application />}
            auth={["application"]}
          />
        </AuthRoute>
        <AuthRoute path="*" element={<NotFound />} />
      </Routes>
    ),
  });

这样就完成了,是不是很傻瓜式呢?

权限说明

若当前 home 的权限被设置为 ["auth1", "auth2", "auth3"],当前用户的权限只要满足一个就会判断为拥有此路由的权限。

动态菜单

react-router-auth-plus 会自动将 children 传给 Layout,你不必在路由配置里传给 Layout。如果你是 ts,将 routers 类型设置为可选即可。useAuthMenus 会过滤掉没有权限的路由,接下来你可以自行处理一下成你想要的数据再渲染成 antd 的 Menu 组件。

import { useAuthMenus, AuthRouterObject } from "react-router-auth-plus";

interface LayoutProps {
  routers?: AuthRouterObject;
}

const Layout:FC<LayoutProps> = ({ routers }) => {
   const menus = useAuthMenus(routers);
   
   ...
}

最后

这是我第一次在掘金发文章,这个 library 是在上班摸鱼时候写出来的(真的没事做啊!)。有什么改进意见可以提出来,如果你觉得还不错的话,点一下 star 吧!