前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >使用React-Router实现前端路由鉴权

使用React-Router实现前端路由鉴权

作者头像
蒋鹏飞
发布2020-10-15 10:05:47
2.3K0
发布2020-10-15 10:05:47
举报
文章被收录于专栏:进击的大前端进击的大前端

React-Router是React生态里面很重要的一环,现在React的单页应用的路由基本都是前端自己管理的,而不像以前是后端路由,React管理路由的库常用的就是React-Router。本文想写一下React-Router的使用,但是光介绍API又太平淡了,而且官方文档已经写得很好了,我这里就用一个常见的开发场景来看看React-Router是怎么用的吧。我们一般的系统都会有用户访问权限的限制,某些页面可能需要用户具有一定的权限才能访问。本文就是用React-Router来实现一个前端鉴权模型。

本文全部代码已经上传GitHub,大家可以拿下来玩玩:github.com/dennis-jian…

应用示例

本文要实现的功能是大家经常遇到的场景,就是要控制不同的用户角色来访问不同的页面,这里总共有四个页面:

  1. /index: 网站首页
  2. /login: 登录页
  3. /backend:后台页面
  4. /admin:管理页面

另外还有三种角色:

  1. 未登录用户:只能访问网站首页/index和登录页/login
  2. 普通用户:可以访问网站首页/index,登录页/login和后台页面/backend
  3. 管理员:可以访问管理页面/admin和其他所有页面

引入React-Router

要实现路由鉴权,我们还得一步一步来,我们先用React-Router搭建一个简单的带有这几个页面的项目。我们直接用create-react-app创建一个新项目,然后建了一个pages文件夹,里面放入我们前面说的那几个页面:

我们页面先写简单点,先写个标题吧,比如这样:

代码语言:javascript
复制
import React from 'react';

function Admin() {
  return (
    <h1>管理员页面h1>
  );
}
复制代码

其他几个页面也是类似的。

然后我们就可以在App.js里面引入React-Router做路由跳转了,注意我们在浏览器上使用的是react-router-dom,新版的React-Router将核心逻辑层和展示层分开了,核心逻辑会处理路由匹配等,展示层会处理实际的跳转和路由变化的监听,之所以这么分,是因为React-Router不仅仅需要支持浏览器,还需要支持React Native,这两个平台的监听和跳转是不一样的,所以现在React-Router下面有好几个包了:

react-router:核心逻辑处理,提供一些公用的基类 react-router-dom:具体实现浏览器相关的路由监听和跳转 react-router-native:具体实现RN相关的路由监听和跳转

在实际使用时,我们一般不需要引用react-router,而是直接用react-router-dom就行,因为它自己会去引用react-router。下面我们在项目里面引入react-router-dom

代码语言:javascript
复制
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 (
    
      
        
        
        
        
      
    
  );
}

export default App;
复制代码

然后可以在Home页面用Link加上跳转到其他页面的链接,这样就可以跳转了:

代码语言:javascript
复制
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. 管理员页面:只有管理员才能访问的页面

为了好管理这三种页面,我们可以将他们抽取成三个文件,放到一个独立的文件夹routes里面,三个文件分别命名为publicRoutes.jsprivateRoutes.jsadminRoutes.js

对于每个路由文件,我们可以将这类路由组织成数组,然后export出去给外面调用,比如publicRoutes.js

代码语言:javascript
复制
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;

然后我们外面使用的地方直接改为:

代码语言:javascript
复制
import publicRoutes from './routes/publicRoutes';

function App() {
  return (
    
      
        {publicRoutes.map(
          ({path, component, ...routes}) => 
            
        )}
        
        
      
    
  );
}
复制代码

这样我们的App.js里面就不会有冗长的路由路由列表了,而是只需要循环一个数组就行了。但是对于需要登录才能访问的页面和管理员页面我们不能直接渲染Route组件,我们最好再封装一个高级组件,将鉴权的工作放到这个组件里面去,这样我们普通的页面在实现时就不需要关心怎么鉴权了。

封装高级组件

要封装这个鉴权组件思路也很简单,前面我们将publicRoutes直接拿来循环渲染了Route组件,我们的鉴权组件只需要在这个基础上再加一个逻辑就行了:在渲染真正的Route组件前先检查一下当前用户是否有对应的权限,如果有就直接渲染Route组件,如果没有就返回某个页面,可以是登录页或者后台首页,具体根据自己项目需求来。所以我们的路由配置文件privateRoutes.jsadminRoutes.js里面的路由会比publicRoutes.js的多两个参数:

代码语言:javascript
复制
// privateRoutes.js
import Backend from '../pages/Backend';

const privateRoutes = [
  {
    path: '/backend',
    component: Backend,
    exact: true,
    role: 'user',       // 当前路由需要的角色权限
    backUrl: '/login'   // 不满足权限跳转的路由
  },
];

export default privateRoutes;

adminRoutes.js是类似的写法:

代码语言:javascript
复制
// 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'],具体的权限验证逻辑要看自己项目权限的设计,这里只是一个例子:

代码语言:javascript
复制
// 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 
  } else {
    // 如果没有权限,返回配置的默认路由
    return 
  }
}

export default AuthRoute;
复制代码

然后用我们的AuthRoute的渲染adminRoutesprivateRoutes:

代码语言:javascript
复制
// ... 省略其他代码 ...

{privateRoutes.map(
  (route) => 
)}
{adminRoutes.map(
  (route) => 
)}
复制代码

登录设置权限

在我们的AuthRoute里面用到了user: { role }这个变量,但是我们还没设置它。真实项目中一般是登录的时候后端API会返回当前用户的角色,然后前端将这个权限信息保存在一些状态管理工具里面,比如Redux。我们这里直接在Login页面写死两个按钮来模拟这个权限了,用户的配置就用根组件的state来管理了,Login页面的两个按钮会改变对应的state

代码语言:javascript
复制
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;
复制代码

到这里我们这个简单的路由鉴权就完成了,具体跑起来效果如下:

本文全部代码已经上传GitHub,大家可以拿下来玩玩:github.com/dennis-jian…

总结

  1. React-Router可以用来管理前端的路由跳转,是React生态里面很重要的一个库。
  2. React-Router为了同时支持浏览器和React-Native,他分拆成了三个包react-router核心包,react-router-dom浏览器包,react-router-native支持React-Native。使用时不需要引入react-router,只需要引入需要的平台包就行。
  3. 对于需要不同权限的路由,我们可以将他们拎出来分好类,单独建成一个文件,如果路由不多,放在一个文件导出多个数组也行。
  4. 对于需要鉴权的路由,我们可以用一个高级组件将权限校验的逻辑封装在里面,其他页面只需要加好配置,完全不用关心鉴权的问题。

本文内容偏简单,作为熟悉**React-Router**的用法还不错,但是我们不能只会用,还要知道他的原理。下篇文章我们就来看看**React-Router**的源码里面蕴藏了什么奥秘,大家可以点个关注不迷路,哈哈~

参考资料

官方文档:reactrouter.com/web/guides/…

GitHub源码地址:github.com/ReactTraini…

文章的最后,感谢你花费宝贵的时间阅读本文,如果本文给了你一点点帮助或者启发,请不要吝啬你的赞和GitHub小星星,你的支持是作者持续创作的动力。

作者博文GitHub项目地址: github.com/dennis-jian…

作者掘金文章汇总:juejin.im/post/684490…

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 应用示例
  • 引入React-Router
  • 模块划分
  • 封装高级组件
  • 登录设置权限
  • 总结
  • 参考资料
相关产品与服务
访问管理
访问管理(Cloud Access Management,CAM)可以帮助您安全、便捷地管理对腾讯云服务和资源的访问。您可以使用CAM创建子用户、用户组和角色,并通过策略控制其访问范围。CAM支持用户和角色SSO能力,您可以根据具体管理场景针对性设置企业内用户和腾讯云的互通能力。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档