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 组件接收一个名为 config 的 Props,这是一份路由表。同时,由于 FrontendAuth 组件放在了 Switch 组件内部,React Router 还自动为 FrontendAuth 注入了 location 属性,当地址栏的路由发生变化时,就会触发 location 属性对象上的 pathname 属性发生变化,从而触发 FrontendAuth 的更新(调用 render 函数)。
FrontendAuth 的 render 函数中,根据 pathname 查找到路由表中的相关配置,如果该配置中指定了无需校验,就直接返回相应的 Route 组件。
如果查找到的配置需要进行校验,再根据是否登陆进行处理,具体可以查看代码中的注释。
总结一下,实现路由守卫需要考虑到以下的问题:
- 未登录情况下,访问不需要权限校验的合法页面:允许访问
- 登陆情况下,访问登陆页面:禁止访问,跳转至主页
- 登陆情况下,访问除登陆页以外的合法页面:允许访问
- 登陆情况下,访问所有的非法页面:禁止访问,跳转至 404
- 未登录情况下,访问需要权限校验的页面:禁止访问,跳转至登陆页
- 未登录情况下,访问所有的非法页面:禁止访问,跳转至 404
作者:黑黢黢
链接:https://www.jianshu.com/p/677433245697
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。
React Router 4.0 实现路由守卫的更多相关文章
- React Router 4.0 ---- 嵌套路由和动态路由
嵌套路由,从广义上来说,分为两种情况:一种是每个路由到的组件都有共有的内容,这时把共有的内容抽离成一个组件,变化的内容也是一个组件,两种组件组合嵌套,形成一个新的组件.另一种是子路由,路由到的组件内部 ...
- react router @4 和 vue路由 详解(七)react路由守卫
完整版:https://www.cnblogs.com/yangyangxxb/p/10066650.html 12.react路由守卫? a.在之前的版本中,React Router 也提供了类似的 ...
- react router 4.0以上的路由应用
thead>tr>th{padding:8px;line-height:1.4285714;border-top:1px solid #ddd}.table>thead>tr& ...
- react router @4 和 vue路由 详解(全)
react router @4 和 vue路由 本文大纲: 1.vue路由基础和使用 2.react-router @4用法 3.什么是包容性路由?什么是排他性路由? 4.react路由有两个重要的属 ...
- 初步学习React Router 4.0
React Router 4.0 是react官方推荐的路由库.4是已经正式发布的最新版本. 初始化项目启动之后: npm run eject 弹出配置文件.自定义配置webpack 查看下pac ...
- React Router 4.0 + webpack 实现组件按需加载
网上关于React Router 4.0的按需加载文章有很多,大致的思路都一样,但是其实具体实现起来却要根据自己的实际情况来定,这里主要介绍一下我的实现方式. 主要方式是通过Route组件的rende ...
- React Router 4.0 体验
React Router 4.0 (以下简称 RR4) 已经正式发布,它遵循React的设计理念,即万物皆组件.所以 RR4 只是一堆 提供了导航功能的组件(还有若干对象和方法),具有声明式(声明式编 ...
- react router @4 和 vue路由 详解(八)vue路由守卫
完整版:https://www.cnblogs.com/yangyangxxb/p/10066650.html 13.vue路由守卫 a.beforeEach 全局守卫 (每个路由调用前都会触发,根据 ...
- React Router V4.0学习笔记
最近在学习React Router,但是网站的教程多半还是3.X版本之前的,所以我只能在GitHub上找到React Router的官方文档在读.后来总结了一下,包括学习经验以及V3.X与V4.X的差 ...
随机推荐
- markdown中设置、调整图片尺寸
使用百分比描述尺寸 <img src="https://img2018.cnblogs.com/blog/1122471/201902/1122471-2019022218575673 ...
- 学习Road map Part 03 编程和算法
方法: 优先重复已学过的内容 写学习笔记
- [原]Linux 修改时区
1.查看当前时区 date -R 2.修改当前时区 tzselect 之后会出来一个选项菜单,选择你想要的时区就OK了 3.替换系统时区文件 cp /usr/share/zoneinfo/XXX/YY ...
- 关于notify() 和notifyAll() 一个需要注意的地方
notify() 和 notifyAll()都是唤醒其他正在等待同一个对象锁的线程. 下面是我遇到的一个问题,记下来,免得忘了. 直接上代码,有错误的代码: 代码描述:有一个Caculate类,类中又 ...
- Failed to read candidate component错误
<context:component-scan base-package="com.spdb"/> <mvc:annotation-driven/> 加上该 ...
- Spark系列-SparkSQL实战
Spark系列-初体验(数据准备篇) Spark系列-核心概念 Spark系列-SparkSQL 之前系统的计算大部分都是基于Kettle + Hive的方式,但是因为最近数据暴涨,很多Job的执行时 ...
- 从数据库中取出的数据,字段名为gb2312的 数据转码为utf8
$pj = Pj::find()->where($map)->asArray()->one(); if(!empty($pj)) { foreach ($pj as $k=>$ ...
- 记一次关于SSM框架的使用错误
今天遇到一个十分操蛋的问题,最后发现是因为忘记在对应的Service上加上@AutoWired. 难怪单元测试没问题,因为单元测试中用到的Service,其实现类通过DAO自动装配了.也就是在对应的s ...
- Semi-Supervised Dimensionality Reduction
今天阅读了一篇关于半监督降维的论文,做个总结.这篇论文的全名叫<Semi-Supervised Dimensionality Reduction>(2006),是南大周志华老师的大作. 本 ...
- Ajax全局加载框(Loading效果)的配置
在Ajax进行后台数据请求的过程中,我们有时候会希望用户能知道页面后台还在做一些事情,这时候就需要给用户一个非常明确的提示,也就是我们所谓的进度条 废话完成~ 实现原理: Jquery可以对ajax进 ...