react-router 5.0 的鑒權
當我們使用react-router 控制頁面的路由時候,有些頁面,是需要登錄才能訪問,有些不需要登錄就可以訪問,還有些頁面,是根據用戶的權限來限制訪問的。
如果是傳統的多頁面,只需要后端鑒權就可以了,沒權限就直接后端重定向。
但是單頁面情況下,路由使用了 window.history.statepush 這種情況下,路由的改變,是不會向服務器發送頁面請求的。所以需要前端來鑒權。
一、參考vue的辦法
在vue 里面 路由配置為 json 格式,所以很方便的使用 路由守衛 , 來控制權限。所以網上有一種辦法,就是利用 react-router-config 來模仿 vue的路由鑒權。
其源碼也不復雜。詳細使用可以參考 。 通過研究以后發現,這似乎並不能滿足我的要求,因為嵌套的子路由好像沒有辦法一次解決,也就是說,每個頁面的嵌套子路由,要單獨的配置json。並且似乎無法在父頁面里面,對子頁面的組件傳props。
二、自己寫一個類似的 Route 組件,並在其里面鑒權
新建一個 RouteGuard.tsx 源碼如下。
import * as React from 'react'; import { Route, Redirect } from 'react-router-dom'; // interface GuardProps { // path:string; // component:React.Component; // permissions?:any[]; // exact?:boolean|undefined; // strict?:boolean|undefined; // otherProps?:object; // } // 可以由mobx注入用戶信息 class Guard extends React.Component<any, any> { constructor(props: any) { super(props); // 假設這里從 mobx 里面拿到了用戶信息 const userinfo = { level: 1 // 假設等級是一般用戶 }; // 如果用戶信息不存在,則需要去登錄 let auth = true; if (!userinfo) { auth = false; } else if (this.props.permissions) { // 如果存在,說明是需要區別等級鑒權的 const permissions = this.props.permissions; if (permissions.indexOf(userinfo.level) === -1) { auth = false; } } this.state = { auth }; } public render() { const ComponentPage = this.props.component; return ( <Route path={this.props.path} exact={this.props.exact || false} strict={this.props.strict || false} render={props => { return ( this.state.auth ? ( <ComponentPage {...props} {...this.props.otherProps} /> ) : ( <Redirect to={{ pathname: '/login', state: { from: props.location } }} /> ) ) } } /> ); } } export default Guard;
使用方式與 Rute 類似,只要在需要鑒權的頁面,使用RouteGuard 組件就可以了,如果不需要鑒權的,依然可以繼續使用原生的 route 組件:
import * as React from 'react'; import { Switch } from 'react-router-dom'; import RouteGuard from "src/RouteGuard"; import Index from "src/pages/main/Index/Index"; class Home extends React.Component<any>{ public componentDidMount(){ console.log(this.props); } public render() { return ( <div className="_Home"> <div className="section base-container"> <Switch> <RouteGuard path="" exact={true} component={Index} /> </Switch> </div> </div> ); } } export default Home;
總結:還可以繼續加入一些判斷,例如移動端和PC端的區別,來渲染不同的組件