Vue 前端应用实现RBAC权限控制的一种方式

上午发布前,感受已经作完了,就接着撸jiiiiiin权限系统 ,但是我发现漏了一个东西,就是一更的时候,针对v-access指令默认模式,经过校验对应资源所需接口列表来检查登陆用户是否具备访问权限,可是那个时候的对比是接口的url,数据结构以下:html

authorizeInterfaces:前端

["admin/dels/*", "admin/search/*/*/*", "admin/*/*/*", "role/list/*", "admin/*"]
复制代码

可是我接着写的时候,发现不知足呀,我后台的接口是RESTful类型的,因此必须校验url+method,那如今的数据结构就变成:vue

authorizeInterfaces:git

[{url: "admin/dels/*", method: "DELETE"}, ....]
复制代码

故由修改了一下,具体能够参考下面的commit:github

修改rbac前端校验模块,使其支持RESTful类型接口校验 ajax

对于使用就两步: 1.增长了一个isRESTfulInterfaces配置:正则表达式

/** * [*] 声明`authorizeInterfaces`集合存储的是RESTful类型的接口仍是常规接口 * 1. 若是是(true),则`authorizeInterfaces`集合须要存储的结构就是: * [{url: 'admin/dels/*', method: 'DELETE'}] * 即进行接口匹配的时候会校验类型 * 2. 若是不是(false),则`authorizeInterfaces`集合须要存储的结构就是,即不区分接口类型: * ['admin/dels/*'] */
    isRESTfulInterfaces = true
复制代码

2.在登陆成功设置$vp.rabcUpdateAuthorizeInterfaces已受权接口列表的时候,你们须要将数据结构构造好。spring

3.针对于RESTful类型接口:v-access="[{url: 'admin/search/*', method: 'POST'}]"json

如今针对v-access指令的值的使用,能够有如下几种状况:后端

  • 若是isRESTfulInterfaces设置为true注意这是默认设置,则使用下面的格式:
v-access="[{url: 'admin/search/*', method: 'POST'}]"
// 或者若是只有一个接口声明
v-access="{url: 'admin/search/*/*/*', method: 'POST'}"
复制代码
  • 若是isRESTfulInterfaces设置为false,则使用下面的格式:
v-access="['admin', 'admin/*']"
复制代码
  • 若是但愿使用别名标识一个资源:
v-access:alias="['LOGIN', 'WELCOME']"
v-access:alias="'LOGIN'"
复制代码
  • 另外以上几种都是如何声明组件所需权限,而若是登陆用户没有这个权限,则组件将会被隐藏,可是也可使用下面的配置让组件变为半透明且不可用点击:
v-access:alias.disable="['LOGIN', 'WELCOME']"
v-access.disable="['admin', 'admin/*']"
复制代码

就是加一个disable而已;

:)

谢谢支持!

更新分割


权限控制无论先后端均可以简单分为:

  • 身份认证权限控制
  • RBAC权限控制
  • ...

而前端我和团队,检索了不少地方都没有很成熟或者说可行的关于 RBAC基于角色的访问控制相关的前端权限控制方案,多是咱们检索的方法不对,亦或是你们都忙于其余,没有时间把本身的方法整理公布出来,故咱们在原定计划中,本身实践了一把,下面和你们分享一下,有不对或者错误的地方,望指正。

若是你们点进来,应该都知道何为RBAC,为何须要使用了,故这里对此不作过多解释,RBAC基于角色的访问控制,通常只会在管理端应用使用,故这个模块不做为默认模块。

下面介绍一下vue-viewplus 一个简化Vue应用开发的工具库中的rabc.js 自定义RBAC权限控制模块。

该模块,意在为前端应用提供rbac权限控制帮助。

其和login-state-check.js 身份认证权限控制模块不一样之处在于,该模块提供了一下两种权限控制手段:

  • 实现前端页面可访问性控制,即经过路由拦截,判断用户待访问页面是否已经受权
  • 实现可见页面的局部UI组件的可以使用性或可见性控制,即基于自定义v-access指令,对比声明的接口或资源别是否已经受权

而login-state-check.js 身份认证权限控制模块,则提供的是对非公共页面的身份认证校验检查,其中维护了用户的身份认证即登陆状态,这种权限控制,更适合大多数应用,即给用户使用的客户端应用。

而当前模块也依赖了登陆状态,故能够一块儿复用;

实际案例:

名称 渠道 简介
jiiiiiin权限系统 PC端 一个先后端分离的内管基础项目,并基于当前插件完成了RBAC前端权限控制

效果以下:

使用方法:

  1. 基于vue-viewplus,实现了一个自定义模块 ,非标准模块,须要手动配置:

main.js入口文件:

import router from './router'
import ViewPlus from 'vue-viewplus'
import rbacModule from '@/plugin/vue-viewplus/rbac.js'
import viewPlusOptions from '@/plugin/vue-viewplus'

Vue.use(ViewPlus, viewPlusOptions)

ViewPlus.mixin(Vue, rbacModule, {
    debug: true,
    errorHandler(err) {
        console.error(err)
    },
    moduleName: '自定义RBAC',
    router,
    publicPaths: ['/login'],
    onLoginStateCheckFail(to, from, next) {
        this.dialog(`您无权访问【${to.path}】页面`)
            .then(() => {
            // 防止用户被踢出以后,被权限拦截致使访问不了任何页面,故这里进行登陆状态监测
            if (this.isLogin()) {
                next(false);
            } else {
                next('/login');
            }
        })
    }
})
复制代码
  1. 在登陆成功以后,须要设置插件的登陆状态,和rabc模块相应权限集合,即后端返回的当前登陆用户拥有的:
  • [*] 登陆用户拥有访问权限的路由path路径集合

    完成该配置,则页面可访问性控制就能够正常工做

  • [*] 登陆用户拥有访问权限的后台接口集合

  • [可选] 登陆用户拥有访问权限的资源别名集合

    完成以上配置,则自定义v-access指令就能够支持对应模式的配置

  • [可选] 是不是超级用户

    有些系统存在一个超级用户角色,其能够访问任何资源、页面,故若是设置,针对这个登陆用户将不会作任何权限校验,以便节省前端资源

// 开始请求登陆接口
      AccountLogin(vm.$vp, {
        username,
        password,
        imageCode
      })
        .then(async res => {
          // 修改用户登陆状态
          vm.$vp.modifyLoginState(true)
          const menus = _delEmptyChildren(res.principal.admin.menus);
          const authorizeResources = _parseAuthorizePaths(res.principal.admin.authorizeResources);
          vm.$vp.rabcUpdateAuthorizedPaths(authorizeResources)
          const authorizeInterfaces = _parseAuthorizeInterfaces(res.principal.admin.authorizeInterfaces);
          vm.$vp.rabcUpdateAuthorizeInterfaces(authorizeInterfaces)
          const isSuperAdminStatus = _parseUserRoleIsSuperAdminStatus(res.principal.admin.roles);
          vm.$vp.rabcUpdateSuperAdminStatus(isSuperAdminStatus)
复制代码

针对须要设置的权限集合,其都是扁平化的一维数组,格式相似:

authorizedPathspublicPaths:

["/mngauth/admin", "/index", "/mngauth"]
复制代码

authorizeInterfaces:

["admin/dels/*", "admin/search/*/*/*", "admin/*/*/*", "role/list/*", "admin/*"]
复制代码

authorizeResourceAlias:

["MNG_USERMNG", "MNG_ROLEMNG"]
复制代码

注意以上数组的值除了能够配置为字符串还能够配置为正则表达式:

[/^((\/Interbus)(?!\/SubMenu)\/.+)$/]
复制代码
  1. 实现可见页面的局部UI组件的可以使用性或可见性配置示例:
<el-form v-access="['admin/search/*/*/*']" slot="search-inner-box" :inline="true" :model="searchForm" :rules="searchRules" ref="ruleSearchForm" class="demo-form-inline">
...
	<el-form-item class="search-inner-btn-box">
        <el-button size="small" type="primary" icon="el-icon-search" @click="onSearch">查询</el-button>
        <el-button size="small" icon="el-icon-refresh" @click="onCancelSubmit">重置</el-button>
      </el-form-item>
</el-form>
复制代码

完成以上配置便可让正常使用当前模块提供的权限控制服务,固然如$vp.modifyLoginState|$vp#isLogin涉及到login-state-check.js 身份认证权限控制模块

计划

针对authorizeInterfaces,后期将会用于在发送ajax请求以前,对待请求的接口和当前集合进行匹配,若是匹配失败说明用户就没有请求权限,则直接不发送后台请求,减小后端没必要要的资源浪费,在完成这个权限匹配,前端基础的权限规则就完整了。

其实实现下来没有想象的那么复杂,能够点击查看源码

相较于理解这一块,我以为理解RBAC原则和表结构,才能更好的理解为何要这么控制,更多的关于后端关于这一块的实践,能够参考jiiiiiin权限系统这个内管项目针对表结构的设计,其后台使用的是spring security来完成后端的RBAC权限控制,并针对当前前端权限须要和vue router path进行了细微变化,相较于传统的RBAC 金典5张表的设计。

也请你们多多支持 :)

下面是改模块的api描述:

配置

debug|errorHandler|router|installed配置,能够查看全局通用配置

publicPaths

/** * [*] 系统公共路由path路径集合,便可以让任何人访问的页面路径 * {Array<Object>} * <p> * 好比登陆页面的path,由于登陆以前咱们是没法判断用户是否能够访问某个页面的,故须要这个配置,固然若是须要这个配置也能够在初始化插件以前从服务器端获取,这样先后端动态性就更高,可是通常没有这种需求:) * <p> * 数组中的item,能够是一个**正则表达式字面量**,如`[/^((\/Interbus)(?!\/SubMenu)\/.+)$/]`,也能够是一个字符串 * <p> * 匹配规则:若是在`LoginStateCheck#publicPaths`**系统公共路由path路径集合**中,那么就直接跳过权限校验 */
publicPaths = []
复制代码

authorizedPaths

/** * [*] 登陆用户拥有访问权限的路由path路径集合 * {Array<Object>} * <p> * 数组中的item,能够是一个**正则表达式字面量**,如`[/^((\/Interbus)(?!\/SubMenu)\/.+)$/]`,也能够是一个字符串 * <p> * 匹配规则:若是在`LoginStateCheck#authorizedPaths`**须要身份认证规则集**中,那么就须要查看用户是否登陆,若是没有登陆就拒绝访问 */
authorizedPaths = []
复制代码

authorizeInterfaces

/** * [*] 登陆用户拥有访问权限的后台接口集合 * {Array<Object>} * <p> * 1.在`v-access`指令配置为url(默认)校验格式时,将会使用该集合和指令声明的待审查受权接口列表进行匹配,若是匹配成功,则指令校验经过,不然校验不经过,会将对应dom元素进行处理 * 2.TODO 将会用于在发送ajax请求以前,对待请求的接口和当前集合进行匹配,若是匹配失败说明用户就没有请求权限,则直接不发送后台请求,减小后端没必要要的资源浪费 * <p> * 数组中的item,能够是一个**正则表达式字面量**,如`[/^((\/Interbus)(?!\/SubMenu)\/.+)$/]`,也能够是一个字符串 * <p> * 匹配规则:将会用于在发送ajax请求以前,对待请求的接口和当前集合进行匹配,若是匹配失败说明用户就没有请求权限,则直接不发送后台请求,减小后端没必要要的资源浪费 */
    authorizeInterfaces = []
复制代码

authorizeResourceAlias

/** * [可选] 登陆用户拥有访问权限的资源别名集合 * {Array<Object>} * <p> * 数组中的item,能够是一个**正则表达式字面量**,如`[/^((\/Interbus)(?!\/SubMenu)\/.+)$/]`,也能够是一个字符串 * <p> * 匹配规则:由于若是都用`LoginStateCheck#authorizeInterfaces`接口进行匹配,可能有一种状况,访问一个资源,其须要n个接口,那么咱们在配置配置权限指令:v-access="[n, n....]"的时候就须要声明全部须要的接口,就会须要对比屡次, * 当咱们系统的接口集合很大的时候,势必会成为一个瓶颈,故咱们能够为资源声明一个别名,这个别名则能够表明这n个接口,这样的话就从n+减小到n次匹配; */
authorizeResourceAlias = []
复制代码

onLoginStateCheckFail

/** * [*] `$vp::onLoginStateCheckFail(to, from, next)` * <p> * 权限检查失败时被回调 */
onLoginStateCheckFail = null
复制代码

API接口

modifyLoginState

/** * 代理`$vp#login-state-check`模块的同名方法,以实如今登出、会话超时踢出的时候清理本模块维护的登陆以后设置的状态 * @param status */
  modifyLoginState(status = false)
复制代码

rabcUpdateSuperAdminStatus

/** * 【可选】有些系统存在一个超级用户角色,其能够访问任何资源、页面,故若是设置,针对这个登陆用户将不会作任何权限校验,以便节省前端资源 * @param status */
  rabcUpdateSuperAdminStatus(status)
复制代码

rabcAddAuthorizedPaths

/** * 添加受权路径集合 * 如:登陆完成以后,将用户被受权能够访问的页面`paths`添加到`LoginStateCheck#authorizedPaths`中 * @param paths */
  rabcAddAuthorizedPaths(paths)
复制代码

rabcUpdateAuthorizedPaths

/** * 更新受权路径集合 * @param paths */
  rabcUpdateAuthorizedPaths(paths)
复制代码

rabcUpdateAuthorizeResourceAlias

/** * 更新资源别名集合 * @param alias */
  rabcUpdateAuthorizeResourceAlias(alias)
复制代码

rabcAddAuthorizeResourceAlias

/** * 添加资源别名集合 * @param alias */
  rabcAddAuthorizeResourceAlias(alias)
复制代码

rabcUpdatePublicPaths

/** * 更新公共路径集合 * @param paths */
  rabcUpdatePublicPaths(paths)
复制代码

rabcAddPublicPaths

/** * 添加公共路径集合 * @param paths */
  rabcAddPublicPaths(paths)
复制代码

若是你们以为有用,请你们多多支持,更多的模块请点击查看

相关文章
相关标签/搜索