上午发布前,感觉已经做完了,就接着撸jiiiiiin权限系统 ,可是我发现漏了一个东西,就是一更的时候,针对v-access
指令默认模式,通过校验对应资源所需接口列表来检查登录用户是否具有访问权限,但是那个时候的对比是接口的url,数据结构如下:
authorizeInterfaces
:
["admin/dels/*", "admin/search/*/*/*", "admin/*/*/*", "role/list/*", "admin/*"]
复制代码
但是我接着写的时候,发现不满足呀,我后台的接口是RESTful类型的,所以必须校验url+method
,那现在的数据结构就变成:
authorizeInterfaces
:
[{url: "admin/dels/*", method: "DELETE"}, ....]
复制代码
故由修改了一下,具体可以参考下面的commit:
修改rbac前端校验模块,使其支持RESTful类型接口校验
对于使用就两步: 1.增加了一个isRESTfulInterfaces
配置:
/**
* [*] 声明`authorizeInterfaces`集合存储的是RESTful类型的接口还是常规接口
* 1. 如果是(true),则`authorizeInterfaces`集合需要存储的结构就是:
* [{url: 'admin/dels/*', method: 'DELETE'}]
* 即进行接口匹配的时候会校验类型
* 2. 如果不是(false),则`authorizeInterfaces`集合需要存储的结构就是,即不区分接口类型:
* ['admin/dels/*']
*/
isRESTfulInterfaces = true
复制代码
2.在登录成功设置$vp.rabcUpdateAuthorizeInterfaces
已授权接口列表的时候,大家需要将数据结构构造好。
3.针对于RESTful类型接口:v-access="[{url: 'admin/search/*', method: 'POST'}]"
现在针对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前端权限控制 |
效果如下:
使用方法:
- 其基于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');
}
})
}
})
复制代码
- 在登录成功之后,需要设置插件的登录状态,和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)
复制代码
针对需要设置的权限集合,其都是扁平化的一维数组,格式类似:
authorizedPaths
和publicPaths
:
["/mngauth/admin", "/index", "/mngauth"]
复制代码
authorizeInterfaces
:
["admin/dels/*", "admin/search/*/*/*", "admin/*/*/*", "role/list/*", "admin/*"]
复制代码
authorizeResourceAlias
:
["MNG_USERMNG", "MNG_ROLEMNG"]
复制代码
注意以上数组的值除了可以配置为字符串还可以配置为正则表达式:
[/^((\/Interbus)(?!\/SubMenu)\/.+)$/]
复制代码
- 实现可见页面的局部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
publicPaths = []
复制代码
authorizedPaths
/**
* [*] 登录用户拥有访问权限的路由path路径集合
* {Array
authorizedPaths = []
复制代码
authorizeInterfaces
/**
* [*] 登录用户拥有访问权限的后台接口集合
* {Array
authorizeInterfaces = []
复制代码
authorizeResourceAlias
/**
* [可选] 登录用户拥有访问权限的资源别名集合
* {Array
authorizeResourceAlias = []
复制代码
onLoginStateCheckFail
/**
* [*] `$vp::onLoginStateCheckFail(to, from, next)`
*
* 权限检查失败时被回调
*/
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)
复制代码
如果大家觉得有用,请大家多多支持,更多的模块请点击查看
-
系列文章
- 用Vue来进行移动Hybrid开发和客户端间数据传输的一种方法
- Vue 页面状态保持页面间数据传输的一种方法
- Vue 前端应用进行身份认证权限控制的一种方法
- Vue 减少和服务端交互的样板代码一种方法
- Vue 前端应用进行身份认证权限控制的一种方法