React Router 4.0 實現路由守衛


在使用 Vue 或者 Angular 的時候,框架提供了路由守衛功能,用來在進入某個路有前進行一些校驗工作,如果校驗失敗,就跳轉到 404 或者登陸頁面,比如 Vue 中的 beforeEnter 函數:

...
router.beforeEach(async(to, from, next) => { const toPath = to.path; const fromPath = from.path; }) ... 

在之前的版本中,React Router 也提供了類似的 onEnter 鈎子,但在 React Router 4.0 版本中,取消了這個方法。React Router 4.0 采用了聲明式的組件,路由即組件,要實現路由守衛功能,就得我們自己去寫了。
如果不使用路由守衛,Router 組件是這樣子的:

import * as React from 'react'; import { HashRouter,Switch,Route,Redirect } from 'react-router-dom'; import { HomePage } from '../pages/home/home.page'; import { LoginPage } from '../pages/login/login.page'; import { ErrorPage } from '../pages/error/error.page'; export const Router = () => ( <HashRouter> <Switch> <Route path="/" exact component={HomePage}/> <Route path="/login" exact component={LoginPage}/> <Route path="/home" exact component={HomePage}/> <Route path="/404" exact component={ErrorPage}/> <Redirect to="/404" /> </Switch> </HashRouter> ); 

上面的 Router 組件,包含了三個頁面:

  • 登陸
  • 主頁
  • 404 頁面

以及四個路由:

  • 根路由
  • 登陸路由
  • 主頁路由
  • 404 路由

其中,根路由和 /home 路由,都定向到了主頁路由。
以上是一個基本的路由定義,可以在登陸/主頁和 404 頁面之間來回跳轉,但也有一些問題:

  • 非登陸狀態下,可以直接跳轉到主頁
  • 登陸狀態下,也可以輸入 /login 路由跳轉到登錄頁

現在,我們想完成這樣的功能:

  • 非登陸狀態下,無法直接跳轉到主頁,如果在非登陸狀態下進行主頁跳轉,需要重定向至登陸路由
  • 登陸狀態下,無法跳轉至登錄頁,如果在登陸狀態下進行登陸頁跳轉,需要重定向至主頁路由

要完成這個功能,有兩種方案:

  • 在每個組件中,根據 props 上的 history 對象來進行跳轉
  • 進行全局的路由守衛處理

第一種方式,實現起來比較簡單,但有很多的代碼量,這里主要介紹第二種方式。
在 React Router 4.0 中,沒有再像之前的版本那樣,提供 onEnter 這樣的全局跳轉鈎子,因此要通過高階組件的方式去處理。
下面是我的實現方式,首先,准備一份路由表,包含了路由的地址,組件以及是否需要權限校驗:

import { HomePage } from '../pages/home/home.page'; import { LoginPage } from '../pages/login/login.page'; import { ErrorPage } from '../pages/error/error.page'; interface routerConfigModel { path:string, component?:any, auth?:boolean } export const routerConfig:routerConfigModel[] = [ { path:'/', component:HomePage, auth:true, },{ path:'/home', component:HomePage, auth:true, },{ path:'/login', component:LoginPage, },{ path:'/404', component:ErrorPage } ]; 

auth 設置為 true,表示該路由需要權限校驗。
然后,定義 Router 組件,該組件是經過高階組件包裝后的結果:

import * as React from 'react'; import { HashRouter,Switch } from 'react-router-dom'; import { FrontendAuth } from '../components/frontend-auth/frontend-auth.component' import { routerConfig } from './router.config' export class Router extends React.Component{ render(){ return( <HashRouter> <Switch> <FrontendAuth config={routerConfig} /> </Switch> </HashRouter> ); } } 

所有的路由跳轉,都交給 FrontendAuth 高階組件代理完成。下面是 FrontendAuth 組件的實現:

import * as React from 'react'; import { Route,Redirect } from 'react-router-dom'; import { propsModel } from './frontend-auth.model' export class FrontendAuth extends React.Component<any,propsModel>{ render(){ const { location,config } = this.props; const { pathname } = location; const isLogin = localStorage.getItem('__config_center_token') // 如果該路由不用進行權限校驗,登錄狀態下登陸頁除外 // 因為登陸后,無法跳轉到登陸頁 // 這部分代碼,是為了在非登陸狀態下,訪問不需要權限校驗的路由 const targetRouterConfig = config.find((v:any) => v.path === pathname); if(targetRouterConfig && !targetRouterConfig.auth && !isLogin){ const { component } = targetRouterConfig; return <Route exact path={pathname} component={component} /> } if(isLogin){ // 如果是登陸狀態,想要跳轉到登陸,重定向到主頁 if(pathname === '/login'){ return <Redirect to='/' /> }else{ // 如果路由合法,就跳轉到相應的路由 if(targetRouterConfig){ return <Route path={pathname} component={targetRouterConfig.component} /> }else{ // 如果路由不合法,重定向到 404 頁面 return <Redirect to='/404' /> } } }else{ // 非登陸狀態下,當路由合法時且需要權限校驗時,跳轉到登陸頁面,要求登陸 if(targetRouterConfig && targetRouterConfig.auth){ return <Redirect to='/login' /> }else{ // 非登陸狀態下,路由不合法時,重定向至 404 return <Redirect to='/404' /> } } } } 

以及對應的 Model:

export interface propsModel { config:any[], } 

頁面上的路由跳轉,都由 FrontendAuth 高階組件代理了,在 Switch 組件內部,不再是 Route 組件,而只有一個 FrontendAuth 組件。
FrontendAuth 組件接收一個名為 configProps,這是一份路由表。同時,由於 FrontendAuth 組件放在了 Switch 組件內部,React Router 還自動為 FrontendAuth 注入了 location 屬性,當地址欄的路由發生變化時,就會觸發 location 屬性對象上的 pathname 屬性發生變化,從而觸發 FrontendAuth 的更新(調用 render 函數)。
FrontendAuthrender 函數中,根據 pathname 查找到路由表中的相關配置,如果該配置中指定了無需校驗,就直接返回相應的 Route 組件。
如果查找到的配置需要進行校驗,再根據是否登陸進行處理,具體可以查看代碼中的注釋。

總結一下,實現路由守衛需要考慮到以下的問題:

  1. 未登錄情況下,訪問不需要權限校驗的合法頁面:允許訪問
  2. 登陸情況下,訪問登陸頁面:禁止訪問,跳轉至主頁
  3. 登陸情況下,訪問除登陸頁以外的合法頁面:允許訪問
  4. 登陸情況下,訪問所有的非法頁面:禁止訪問,跳轉至 404
  5. 未登錄情況下,訪問需要權限校驗的頁面:禁止訪問,跳轉至登陸頁
  6. 未登錄情況下,訪問所有的非法頁面:禁止訪問,跳轉至 404


作者:黑黢黢
鏈接:https://www.jianshu.com/p/677433245697
來源:簡書
簡書著作權歸作者所有,任何形式的轉載都請聯系作者獲得授權並注明出處。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM