乐趣区

关于javascript:使用ReactRouter实现前端路由鉴权

React-Router是 React 生态外面很重要的一环,当初 React 的单页利用的路由根本都是前端本人治理的,而不像以前是后端路由,React 治理路由的库罕用的就是 React-Router。本文想写一下React-Router 的应用,然而光介绍 API 又太平淡了,而且官网文档曾经写得很好了,我这里就用一个常见的开发场景来看看 React-Router 是怎么用的吧。咱们个别的零碎都会有用户拜访权限的限度,某些页面可能须要用户具备肯定的权限能力拜访。本文就是用 React-Router 来实现一个前端鉴权模型。

本文全副代码曾经上传 GitHub,大家能够拿下来玩玩:https://github.com/dennis-jiang/Front-End-Knowledges/tree/master/Examples/React/react-router-usage

利用示例

本文要实现的性能是大家常常遇到的场景,就是要管制不同的用户角色来拜访不同的页面,这里总共有四个页面:

  1. /index: 网站首页
  2. /login: 登录页
  3. /backend:后盾页面
  4. /admin:治理页面

另外还有三种角色:

  1. 未登录用户 :只能拜访网站首页/index 和登录页/login
  2. 普通用户 :能够拜访网站首页/index,登录页/login 和后盾页面/backend
  3. 管理员 :能够拜访治理页面/admin 和其余所有页面

引入 React-Router

要实现路由鉴权,咱们还得一步一步来,咱们先用 React-Router 搭建一个简略的带有这几个页面的我的项目。咱们间接用 create-react-app 创立一个新我的项目,而后建了一个 pages 文件夹,外面放入咱们后面说的那几个页面:

咱们页面先写简略点,先写个题目吧,比方这样:

import React from 'react';

function Admin() {
  return (<h1> 管理员页面 </h1>);
}

其余几个页面也是相似的。

而后咱们就能够在 App.js 外面引入 React-Router 做路由跳转了,留神咱们在浏览器上应用的是 react-router-dom,新版的React-Router 将外围逻辑层和展现层离开了,外围逻辑会解决路由匹配等,展现层会解决理论的跳转和路由变动的监听,之所以这么分,是因为 React-Router 不仅仅须要反对浏览器,还须要反对 React Native,这两个平台的监听和跳转是不一样的,所以当初 React-Router 上面有好几个包了:

react-router:外围逻辑解决,提供一些专用的基类

react-router-dom:具体实现浏览器相干的路由监听和跳转

react-router-native:具体实现 RN 相干的路由监听和跳转

在理论应用时,咱们个别不须要援用 react-router,而是间接用react-router-dom 就行,因为它本人会去援用react-router。上面咱们在我的项目外面引入react-router-dom

import React from 'react';
import {
  BrowserRouter as Router,
  Switch,
  Route,
} from "react-router-dom";
import Home from './pages/Home';
import Login from './pages/Login';
import Backend from './pages/Backend';
import Admin from './pages/Admin';

function App() {
  return (
    <Router>
      <Switch>
        <Route path="/login" component={Login}/>
        <Route path="/backend" component={Backend}/>
        <Route path="/admin" component={Admin}/>
        <Route path="/" component={Home}/>
      </Switch>
    </Router>
  );
}

export default App;

而后能够在 Home 页面用 Link 加上跳转到其余页面的链接,这样就能够跳转了:

import React from 'react';
import {Link} from 'react-router-dom';

function Home() {
  return (
    <>
      <h1> 首页 </h1>
      <ul>
        <li><Link to="/login"> 登录 </Link></li>
        <li><Link to="/backend"> 后盾 </Link></li>
        <li><Link to="/admin"> 管理员 </Link></li>
      </ul>
    </>
  );
}

export default Home;

到当初咱们的利用运行起来是这样的:

模块划分

尽管咱们的跳转实现了,然而所有人都能够拜访任何页面,咱们后面的需要是要依据登录的角色限度拜访的页面的,在写代码前,咱们先来思考下应该怎么做这个。当然最直观最简略的办法就是每个页面都检测下以后用户的角色,匹配不上就报错或者跳回首页。咱们当初只有几个页面,这样做如同也还好,然而如果咱们的利用变大了,页面变多了,每个页面都来一次检测就显得很反复了,所以咱们应该换个角度来思考这个问题。

认真一看,其实咱们总共就三种角色,对应三种不同的权限,这三个权限还有层级关系,高级别的权限蕴含了低级别的权限,所以咱们的页面也能够依照这些权限分为三种:

  1. 公共页面:所有人都能够拜访,没登录也能够拜访,包含网站首页和登录页
  2. 一般页面:一般登录用户能够拜访的页面
  3. 管理员页面:只有管理员能力拜访的页面

为了好治理这三种页面,咱们能够将他们抽取成三个文件,放到一个独立的文件夹 routes 外面,三个文件别离命名为publicRoutes.jsprivateRoutes.jsadminRoutes.js

对于每个路由文件,咱们能够将这类路由组织成数组,而后 export 进来给里面调用,比方publicRoutes.js

import Login from '../pages';
import Home from '../pages/Home';

const publicRoutes = [
  {
    path: '/login',
    component: Login,
    exact: true,
  },
  {
    path: '/',
    component: Home,
    exact: true,
  },
];

export default publicRoutes;

而后咱们里面应用的中央间接改为:

import publicRoutes from './routes/publicRoutes';

function App() {
  return (
    <Router>
      <Switch>
        {publicRoutes.map(({path, component, ...routes}) => 
            <Route key={path} path={path} component={component} {...routes}/>
        )}
        <Route path="/backend" component={Backend}/>
        <Route path="/admin" component={Admin}/>
      </Switch>
    </Router>
  );
}

这样咱们的 App.js 外面就不会有简短的路由路由列表了,而是只须要循环一个数组就行了。然而对于须要登录能力拜访的页面和管理员页面咱们不能间接渲染 Route 组件,咱们最好再封装一个高级组件,将鉴权的工作放到这个组件外面去,这样咱们一般的页面在实现时就不须要关怀怎么鉴权了。

封装高级组件

要封装这个鉴权组件思路也很简略,后面咱们将 publicRoutes 间接拿来循环渲染了 Route 组件,咱们的鉴权组件只须要在这个根底上再加一个逻辑就行了:在渲染真正的 Route 组件前先检查一下以后用户是否有对应的权限,如果有就间接渲染 Route 组件,如果没有就返回某个页面,能够是登录页或者后盾首页,具体依据本人我的项目需要来。所以咱们的路由配置文件 privateRoutes.jsadminRoutes.js 外面的路由会比 publicRoutes.js 的多两个参数:

// privateRoutes.js
import Backend from '../pages/Backend';

const privateRoutes = [
  {
    path: '/backend',
    component: Backend,
    exact: true,
    role: 'user',       // 以后路由须要的角色权限
    backUrl: '/login'   // 不满足权限跳转的路由
  },
];

export default privateRoutes;

adminRoutes.js是相似的写法:

// adminRoutes.js
import Admin from '../pages/Admin';

const adminRoutes = [
  {
    path: '/admin',
    component: Admin,
    exact: true,
    role: 'admin',       // 须要的权限是 admin
    backUrl: '/backend'  // 不满足权限跳回后盾页面
  },
];

export default adminRoutes;

而后就能够写咱们的高级组件了,咱们将它命名为 AuthRoute 吧,留神咱们这里假如的用户登录时后端 API 会返回给咱们以后用户的角色,一个用户可能有多个角色,比方普通用户的角色是['user'],管理员的角色是['user', 'admin'],具体的权限验证逻辑要看本人我的项目权限的设计,这里只是一个例子:

// AuthRoute.js
import React from 'react';
import {Route, Redirect} from 'react-router-dom';

function AuthRoute(props) {
  const {
    user: {role: userRole},
    role: routeRole,
    backUrl,
    ...otherProps
  } = props;

  // 如果用户有权限,就渲染对应的路由
  if (userRole && userRole.indexOf(routeRole) > -1) {return <Route {...otherProps} />
  } else {
    // 如果没有权限,返回配置的默认路由
    return <Redirect to={backUrl} />
  }
}

export default AuthRoute;

而后用咱们的 AuthRoute 的渲染 adminRoutesprivateRoutes:

// ... 省略其余代码 ...

{privateRoutes.map((route) => <AuthRoute key={route.path} {...route}/>
)}
{adminRoutes.map((route) => <AuthRoute key={route.path} {...route}/>
)}

登录设置权限

在咱们的 AuthRoute 外面用到了 user: {role} 这个变量,然而咱们还没设置它。实在我的项目中个别是登录的时候后端 API 会返回以后用户的角色,而后前端将这个权限信息保留在一些状态管理工具外面,比方 Redux。咱们这里间接在Login 页面写死两个按钮来模仿这个权限了,用户的配置就用根组件的 state 来治理了,Login页面的两个按钮会扭转对应的state

import React from 'react';
import {Link} from 'react-router-dom';

function Login(props) {const {loginAsUser, loginAsAdmin, history} = props;

  const userLoginHandler = () => {loginAsUser();      // 调用父级办法设置用户权限
    history.replace('/backend');     // 登录后跳转后盾页面
  }

  const adminLoginHandler = () => {loginAsAdmin();     // 调用父级办法设置管理员权限
    history.replace('/admin');     // 登录后跳转管理员页面
  }

  return (
    <>
      <h1> 登录页 </h1>
      <button onClick={userLoginHandler}> 普通用户登录 </button>
      <br/><br/>
      <button onClick={adminLoginHandler}> 管理员登录 </button>
      <br/><br/>
      <Link to="/"> 回首页 </Link>
    </>
  );
}

export default Login;

到这里咱们这个简略的路由鉴权就实现了,具体跑起来成果如下:

本文全副代码曾经上传 GitHub,大家能够拿下来玩玩:https://github.com/dennis-jiang/Front-End-Knowledges/tree/master/Examples/React/react-router-usage

总结

  1. React-Router能够用来治理前端的路由跳转,是 React 生态外面很重要的一个库。
  2. React-Router为了同时反对浏览器和 React-Native,他分拆成了三个包react-router 外围包,react-router-dom浏览器包,react-router-native反对React-Native。应用时不须要引入react-router,只须要引入须要的平台包就行。
  3. 对于须要不同权限的路由,咱们能够将他们拎进去分好类,独自建成一个文件,如果路由不多,放在一个文件导出多个数组也行。
  4. 对于须要鉴权的路由,咱们能够用一个高级组件将权限校验的逻辑封装在外面,其余页面只须要加好配置,齐全不必关怀鉴权的问题。

本文内容偏简略,作为相熟 React-Router 的用法还不错,然而咱们不能只会用,还要晓得他的原理。下篇文章咱们就来看看 React-Router 的源码外面蕴藏了什么神秘,大家能够点个关注不迷路,哈哈~

参考资料

官网文档:https://reactrouter.com/web/guides/quick-start

GitHub 源码地址:https://github.com/ReactTraining/react-router/tree/master/packages

文章的最初,感激你破费贵重的工夫浏览本文,如果本文给了你一点点帮忙或者启发,请不要悭吝你的赞和 GitHub 小星星,你的反对是作者继续创作的能源。

作者博文 GitHub 我的项目地址:https://github.com/dennis-jiang/Front-End-Knowledges

退出移动版