使用React-Router實現前端路由鑑權

Reacr-Router 是React生態裏面很重要的一環,如今React的單頁應用的路由由基本都是前端自已管理的,而不像之前是後端路由,React管理路由的庫經常使用的就是 React-Router。本文想寫一下 React-Router的使用,可是光介紹API又太平淡了。並且官方文檔已經寫的很好了,我這裏就用一個常見的開發場景來看看React-Router是怎麼用的吧。咱們通常的系統都會有用戶訪問權限的限制,某些頁面可能須要用戶具備必定的權限才能訪問。本文就是用React-Router來實現一個前端鑑權模型。前端

應用示例


本文要實現的功能是你們常常遇到的場景,就是要控制不一樣的用戶角色來訪問不一樣的頁面,這裏總共有四個頁面:react

  1. /index : 網站首頁後端

  2. /login : 登陸頁數組

  3. /backend : 後臺頁面瀏覽器

  4. /admin : 管理頁面markdown

另外還有三種角色:react-router

  1. 未登陸用戶 : 只能訪問網站首頁/index和登陸頁/loginapp

  2. 普通用戶 : 能夠訪問網站首頁/index,登陸頁/login和後臺頁面/backenddom

  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下面有好幾個包了:

  1. react-router : 核心邏輯處理,提供一些公用的基類

  2. react-router-dom : 具體實現瀏覽器相關的路由監聽和跳轉

  3. react-router-native : 具體實現RN相關的路由監聽和跳轉

在實際使用時,咱們通常不須要引用react-router,而是直接用react-router-dom就行,由於它自已會去引用react-router。下面咱們在項目裏面引入react-router-dom。

import React from 'react';

function Admin() {
  return (
    <h1>管理員頁面</h1>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;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. 管理員頁面 : 只有管理員才能訪問的頁面

爲了好管理這三種頁面,咱們能夠將它們抽取成三個文件,放到一個獨立的文件夾router裏面,三個文件分別命名爲: publicRoutes.js,privateRoutes.js,adminRoutes.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裏面就不會有冗長的路由路由列表了,而是隻須要循環一個數組就好了。可是對於須要登陸才能訪問的頁面和管理員頁面咱們不能直接渲染Router組件,咱們最好再封裝一個高級組件,將鑑權的工做放到這個組件裏面去,這樣咱們普通的頁面在實現時就不須要關心怎麼鑑權了。

封裝高級組件


要封裝這個鑑權組件思路也很簡單,前面咱們將publicRoutes直接拿來循環渲染了Router組件,咱們鑑權組件只須要在這個基礎上再加一個邏輯就好了:在渲染真正的Route組件前先檢查一下當前用戶是否有對應的權限,若是有就直接渲染Route組件,若是沒有就返回某個頁面,能夠是登陸頁或者後臺首頁,具體根據自已項目需求來。因此咱們的路由配置文件privateRoutes.js,adminRoutes.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的渲染adminRoutes和privateRoutes:

// ... 省略其餘代碼 ...

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

登陸設置權限


在咱們的AuthRoute裏面用到了user:{ role }這個變量,可是咱們還沒設置它。真實項目中通常是登陸的時候後端API會返回當前用戶的角色,而後前端將這個權限信息保存在一些狀態管理工具裏面,好比Redux。咱們這裏直接在Login頁面寫死兩個按鈕來模擬這個權限了,用戶的配置就用根組件的state來管理了,login頁面的兩個按鈕會改變對應的stare:

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;
複製代碼

到這裏咱們這個簡單的路由鑑權就完成了,具體跑起來的效果以下:

總結


  1. React-Router 能夠用來管理前端的路由跳轉,是React生態裏面很重要的一個庫。

2.React-Router爲了同時支持瀏覽器和React-Native,他分拆成了三個包react-router核心包,react-router-dom瀏覽器包,react-router-native支持React-Native。使用時不須要引入react-router,只須要引入須要的平臺包就行。

  1. 對於須要不一樣權限的路由,咱們能夠將他們拎出來分好類,單獨建成一個文件,若是路由很少,放在一個文件導出多個數組也行。

  2. 對於須要鑑權的路由,咱們能夠用一個高級組件將權限校驗的邏輯封裝在裏面,其餘頁面只須要加好配置,徹底不用關心鑑權的問題。

相關文章
相關標籤/搜索