前端如何来做权限管理?

设计原因
        说道角色管理-永远分不开权限管理,这里我们简单说一下权限管理,权限管理简单来说就是控制用户所能使用当前系统的哪些功能,具体细化到模块,按钮等等。一个用户可能会有多种角色,而一个角色中又会对应着多个页面的权限和接口权限。角色管理往往是基于业务管理需求而预先在系统中设定好的固定标签,每个角色又对应明确的系统权限,它是一个集合的概念,是众多最小权限颗粒的组成。我们通过把权限给这个角色,再把角色给账号,从而实现账号的权限分配,角色管理承担了一个桥梁的作用。引入角色这个概念,可以帮助我们灵活的扩展,使一个账号可以具备多种角色,角色所拥有的系统权限一般不会随意更改,并且角色也不会随着用户的被添加和被移除而进行改变,相较于用户管理而言更加稳定。

业务原因

        随着公司业务的发展,业务越来越大,越来复杂,角色权限起着至关重要的内容。 以现在公司为例: 不同角色有着不同的权限 。
公司领导层:超级管理员 (分配角色权限) 控制整个业务结构以及权限的控制
程序员(前端):开发权限,上线前发布审批,经过leader审查没有问题发布线上代码权限
程序员(后端):开发权限、发布权限,数据库操作权限(开发、测试服务器)正式服务器需要leader审核 审核成功才能发布
测试:发布权限、数据库操作权限(开发、测试服务器)无正式服务器操作权限
产品:控制产品,商品后台的配置,以及运营权限的分配
运营:运营配置项(商品、产品上架下架状态,奖品后台配置,库存控制)
数据(BI)部门:数据的监控和统计权限
角色权限设计的好,能让大家可以各司其职,做好自己的事情,避免在线上环境发生大问题(由于开发修改了运营配置项,修改系统崩溃)
所以说角色管理设计,是至关重要的一环。

常见 RBAC3 原理及前端实现

RBAC3 整合和RBAC0,RBAC1,RBAC2 模型,是RBAC权限管理模型的集大成。

RBAC0

  • 需求:用户—角色—权限 之间均对多对多的关系。通过对用户所拥有的角色和角色所对应的权限进行对应的:访问资源控制,页面权限控制,数据权限控制,和操作权限控制。

  • 前端实现:

    • 实现一个角色创建页面,用户可以创建新角色,并为其添加该用户自身所有的权限。

    • 实现一个角色管理列表页,可以使用户在管理自己创建的角色。

    • 实现一个角色分配页,用户可以为其指定用户分配该用户所拥有的角色。

    • 在用户登录有后端通常会返回一个权限表(数组,或则对象),通过权限表可以明确该用户所拥有的权限,可以在前端对资源访问,页面访问,数据访问,和操作控制做限制。

有时不一定是权限表,可能是一个10进制的整数,需要将其转为二进制,根据后端约定判断权限。

RBAC1

  • 需求:为了简化角色权限分配的流程,RBAC3模型整合了RBAC1的优势,使角色与角色的权限之间成继承关系。
  • 前端实现:在角色创建页面添加继承角色的配置选项,选择角色后自动填充被继承角色的所有权限且只能添加更多权限不能删权限。

RBAC2

  • 需求:为了应对实际业务中的复杂场景,可能存在两种角色之间是互斥关系(如会计和审计),基数限制,先决条件等限制。

  • 前端实现

    • 互斥实现:在角色创建页面添加角色互斥判断字段,在给用户分配角色的时候需要判断,添加的角色中是否互斥,若角色互斥,或角色权限互斥的添加不成功。
    • 基数约束:一个用户角色或权限数量有限,在用户管理页面可以对这个数量进行控制。
    • 先决条件:在为用户添加角色时控制,在为用户赋予高级角色时需要判断该用户当前角色是否在高级角色的下级中。(如:给前端工程师赋予财务总监的角色时不合理的)

设计表结构及逻辑

  • 用户表
  • 角色表
  • 操作节点表
  • 用户和角色对应表
  • 操作和角色对应表
  • 路由规则分为同步和异步
  • 用户登录后,获取用户的权限
  • 根据权限结合异步路由规则生成路由配置
  • 使用 addRoutes 动态添加路由,防止通过 url 地址直接访问到
  • 根据生成的路由配置动态生成菜单

页面访问权限,两种方式

  • 直接将路由表保存在服务端,通过登录返回对应的路由表
  • 给路由设置守卫,通过用户的权限列表将对应的路由添加到路由表中

数据权限设计

  • 根据对应的权限登记展示隐藏页面的操作按钮
  • 不隐藏按钮,在接口访问设置权限验证,对用户做出提示
首先我们先看一下流程
   用户 => 多角色 => 菜单
               => 资源
               => ................
  从这里我们可以看出来 

  用户 > 可拥有多个角色  > 一个角色可拥有多个其他权限 (菜单,资源接口 ,其他... )

  最后 这个用户 拥有的就是 多个角色权限 合并之后的整体权限

  从流程看 我们要先进行 例如 菜单列表( 有哪些菜单)  资源列表( 有哪些接口)等 的管理界面编写

  下一步 把角色需要的 菜单或资源勾选上 这些权限赋给 角色

  最后 把我们定义好的角色( 例如管理员,超级管理员,访客) 赋给 用户

最常见的是分配三个角色:超级管理员、管理员、运营者。

  • 超级管理员 拥有后台所有功能权限;
  • 管理员 拥有除用户管理外的所有功能权限;
  • 运营者 拥有数据查看和部分功能模块的编辑权限;

在开发时:

         一般会根据路由权限的划分,来控制账号可见及可用的路由;
         通过模块接口的增删改查权限划分,来控制账号对接口的调用权限处理;

不同权限的角色需要控制:

  1. 访问的页面权限不同,无权限的页面不能访问,
  2. 不同角色,拥有的功能权限不同,没有对应的资源权限,则不能进行操作

前端根据后端提供的 menuList,resourceList

  1. 不同权限的角色,注册不同的页面路由
  2. 不同权限的角色,显示不同的功能操作

前端根据数据库中的菜单结构和权限信息来渲染一个菜单出来并只显示其有权限的菜单,并在路由守卫中进行权限控制防止手动输入path越权打开页面。

其中一个页面即一个前端页面,比如首页、用户管理页、资源管理页等。
基本思路为:前端路由保持不变,数据库存储菜单结构、页面权限控制(可以直接做成一个页面来方便管理)等,前端根据数据库中的菜单结构和权限信息来渲染一个菜单出来并只显示其有权限的菜单,并在路由守卫中进行权限控制防止手动输入path越权打开页面。

前端路由(vue-router)中需要正常创建页面及路由。

数据库存储菜单结构和页面权限信息,

菜单(目录、非内容页)可以自己创建,不必要求前端路由中有,因为这是指菜单的可视化的组织结构

页面(内容页)必须是前端路由中已有页面,因为这是用户需要访问的内容。

菜单和页面组成上下级关系,一级可以是菜单也可以是内容页,内容页也可以放在菜单下,这样理论(需要页面菜单样式支持)可以组成无限级菜单

菜单和页面的基本属性包括title(对应路由title)、name(对应路由name)、path(对应路由path)、父级、类型(菜单/页面)、是否可见(左侧菜单栏是否显示:部分页面可能是页面内的链接进去)、是否需要验证权限(部分页面比如首页无需验证权限大家都可以进入)

不需要控制权限且不需要显示到左侧菜单的路由这里可以不进行管理,比如404页面等

前台打开后获取获取数据库的所有菜单、页面及结构,根据是否登录、是否需要验证权限等进行控制,或无权限跳转至登录页

用户登录成功后,再获取用户对应的的页面权限列表,使用上一步获得的所有页面、结构和用户拥有权限的列表渲染出一个菜单,只包含此用户拥有权限的,提升用户体检,避免显示大量用户不能访问的菜单影响使用和不必要的功能暴露。

路由守卫中根据上一步获得的权限列表判断每个跳转,无权限可返回404或无权限页面,防止用户手动输入path越权访问

细节:

登录:当用户填写完账号和密码后向服务端验证是否正确,验证通过之后,服务端会返回一个token,拿到token之后(我会将这个token存贮到cookie中,保证刷新页面后能记住用户登录状态),前端会根据token再去拉取一个 user_info 的接口来获取用户的详细信息(如用户权限,用户名等等信息)。

权限验证:通过token获取用户对应的 role,动态根据用户的 role 算出其对应有权限的路由,通过 router.addRoutes 动态挂载这些路由。

权限控制具体实现思路

1)路由级别权限控制:

  • 创建vue实例的时候将vue-router挂载,但这个时候vue-router挂载一些登录或者不用权限的公用的页面。
  • 当用户登录后,获取用role,将role和路由表每个页面的需要的权限作比较,生成最终用户可访问的路由表。
  • 调用router.addRoutes(store.getters.addRouters)添加用户可访问的路由。
  • 使用vuex管理路由表,根据vuex中可访问的路由渲染侧边栏组件。

2)按钮级别权限控制

  • 封装全局指令,与后端返回的权限列表进行对比。用v-if进行控制

在前端这块,角色管理基本就是菜单的管理,根据角色的不同来显示不同的菜单,并且在用户访问的时候要判断当前这个用户是否具有当前这个权限,否则不能访问,可以这样来做

  1. 把菜单做成可配置式的,里面包含以下几个字段

    //路径
    path?: string;
    //图标
    icon?: string;
    //子菜单
    children?: Array;
    //菜单名字
    text: string;
    //菜单权限集合
    auth?: Array;
    
  2. 同时写一个递归函数来生成菜单,判断用户的角色来决定是否生成这个菜单

  3. 同时我会封装一个自己的路由的高阶组件,在进入之前会判断是否具有这个地址的权限,是就跳转过去,否则就跳转到没有权限的页面

创建路由列表和菜单列表(左侧/顶部),两者格式相似,菜单就是多些图标啥的字段

将路由列表分为两部分:登录后才能看的(权限列表)和未登录也能看的(游客列表)

为权限列表里的每个路由添加角色数组字段,里面的角色才能访问此路由

在路由配置文件中添加跳转到新页面前的导航钩子,在里面根据用户登录后返回的角色信息,与权限列表进行比对,计算得出其所能访问的路由列表,保存到 vuex 中

通过 router.addRoutes() 方法,将两个列表拼接起来(Vue 框架)

同样对比计算得出可见的菜单列表,赋值并保存到 vuex 中

显示页面

1、首先角色管理界面布局为头部搜索区域和表格内容区域。头部搜索直接使用el-form组件就好,数据绑定要加上下面的分页组件的数据,这样调查询接口的时候数据会比较方便。表格内容没什么好说的,直接使用el-table就好。

2、其中添加角色和编辑的功能可以使用同一个组件,只是状态不同而已,一个编辑态一个新增态,数据直接在父组件中配置好,如果是编辑则设置这个角色的数据,如果是新增则设置一个空白的数据。保存之后调一个自定义事件来重新刷新这个页面。

3、分配菜单没什么,只是一个el-tree组件加节点点击事件的处理

4、分配资源页面是v-for循环出多个el-checkbox-group来展示的,每一个资源都有一个分类,如果该分类下所以资源都被选中,则该分类为全选状态,否则为半选状态。当点击分类时,判断现在分类的状态。如果是半选的话,则设置为全选,同时分类下所有资源为选中状态。如果当前分类没有被选中的话,即分类下没有资源被选中,则设置为全选。如果是全选的状态,则该分类下的资源全部取消选中。

   1、关于新增与编辑
    这里用的是添加角色与编辑角色用的是一个公共组件,列表中通过是否是字段来通过路由来进行props传参,新增与编辑显示的文案以及调取的借口不同等,如果是新增增什么都不出现,如果是编辑,则获取之前的详情并且回显
   2、关于分配菜单
     复选框树状结构,通过是否勾选来控制分配菜单

按照功能拆分模块

· 筛选功能 使用 el-form 拆分一个组件,“查询搜索” 按钮点击传递给页面及查询的参数

· 添加角色 按钮 弹出 modal 窗

· 底部 table 相关 · table 拆分一个组件

· 分配菜单 和 分配资源 跳转到相应的页面

· 删除事件传 ID 给页面,在页面中调用接口删除 cell,成功后调用 table 列表接口
· 编辑 弹出 modal 窗 并调用 当前 cell 详情的接口,并把服务端返回的角色详情数据回填到 modal 页面对应的数据

Vue 实现

目前主要的设计思路都是基于Vue-Router配合后端返回角色权限定义进行设计。后端返回角色对应路由权限数据,返回形如 { role: ‘admin’, permissions: [‘Order’, …] },
其中permissions对应前端路由页面name,通过这样的形式后端动态返回该角色所具备的权限列表,前端配合router.addRoutes动态注册路由,达到路由级的权限控制。

在后台管理系统中对角色进行权限的分配(包括页面权限和接口权限),页面权限可以根据vue-router的api动态的生成路由表,而接口权限就需要后端的同学去进行校验。

在Vue中权限控制的主体思路,前端会有一份路由表,它表示了每一个路由可访问的权限。当用户登录之后,通过 token 获取用户的 role ,动态根据用户的 role 算出其对应有权限的路由,再通过router.addRoutes动态挂载路由。但这些控制都只是页面级的。

  1. 创建vue实例的时候将vue-router挂载,但这个时候vue-router挂载一些登录或者不用权限的公用的页面。
  2. 当用户登录后,获取用role,将role和路由表每个页面的需要的权限作比较,生成最终用户可访问的路由表。
  3. 调用router.addRoutes(store.getters.addRouters)添加用户可访问的路由。
  4. 使用vuex管理路由表,根据vuex中可访问的路由渲染侧边栏组件。

React 实现

React:利用高阶组件包装路由视图进行权限控制

你可能感兴趣的:(大前端,前端,权限)