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的差 ...
随机推荐
- jQuery插件开发精品教程,让你的jQuery提升一个台阶(转)
原文:http://www.cnblogs.com/Wayou/p/jquery_plugin_tutorial.html 要说jQuery 最成功的地方,我认为是它的可扩展性吸引了众多开发者为其开发 ...
- interaction-oriented architecture - MVC
MVC(Model-View-Controller),它是专门针 对交互系统提出的,所以如果我们要构建一个交互系统,那么我们就可以直接应用MVC模式,然后 在该模式所搭建的场景的启发下去发现Model ...
- Android中跑马灯效果
<com.randy.test1.self.MarqueeText android:id="@+id/btn1" android:layout_width="mat ...
- Centos 7 安装Anaconda3
1.首先下载地址: https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/ 使用清华镜像下载速度快 2.安装 bash Anaconda3-5.1 ...
- Vue通过input筛选数据
<div id="app"> <input v-model='search' /> <ul> <li v-for="item i ...
- SVN工具使用总结
SVN是Subversion的简称,是一个开放源代码的版本控制系统,相较于RCS.CVS,它采用了分支管理系统,它的设计目标就是取代CVS.互联网上很多版本控制服务已从CVS迁移到Subversion ...
- VC++和C语言中常见数据类型转换为字符串的方法
1.短整型(int) itoa(i,temp,10);///将i转换为字符串放入temp中,最后一个数字表示十进制 itoa(i,temp,2); ///按二进制方式转换 2.长整型(long) lt ...
- PAT——1005. 继续(3n+1)猜想 (25)
卡拉兹(Callatz)猜想已经在1001中给出了描述.在这个题目里,情况稍微有些复杂. 当我们验证卡拉兹猜想的时候,为了避免重复计算,可以记录下递推过程中遇到的每一个数.例如对n=3进行验证的时候, ...
- java _this关键字的用法
1:This关键字可以用于从一个构造方法调用另一个构造方法,可以用于避免重复代码 2:this的第二个用于this.xxx表示成员变量,成员变量的作用范围是 类 避免产生歧义 package c ...
- 【luogu P1939 【模板】矩阵加速(数列)】 题解
题目链接:https://www.luogu.org/problemnew/show/P1939 对于矩阵推序列的式子: 由题意知: f[x+1] =1f[x] + 0f[x-1] + 1f[x-2] ...