系统权限控制基础知识

RBAC模型

        RBAC(Role-BasedAccess Control),是基于角色的访问控制,是一种安全策略,它通过在用户和权限之间引入角色概念,来实现对资源的访问控制。在RBAC中,权限与角色相关联,用户通过成为适当角色的成员而得到这些角色的权限。

RBAC支持的安全原则

  • 最小权限原则(即细粒度控制原则):RBAC可将其角色配置成其完成任务所需要的最小权限集

  • 责任分离原则:通过调用相互独立互斥的角色来共同完成敏感的任务而体现,如要求一个计帐员和财务管理员一起参与同一个过帐

  • 数据抽象原则:通过权限的抽象来体现,如财务操作用借款、存款等抽象权限

RBAC的基本数据元素

  • 用户 users:主体,即需要访问系统资源的个体或实体。每个用户都有一个或多个与之关联的角色。用户的身份通过身份验证过程进行确认,以确保其合法性。

  • 角色 roles:核心概念,它代表了一组权限的集合。角色通常根据业务功能或职责进行定义,例如“管理员”、“编辑员”、“访客”等。通过将角色分配给用户,可以实现用户与权限的间接关联,从而简化权限管理。

  • 目标 objects:资源或资产,即用户需要访问的实体。目标可以是文件、数据库、设备、服务或任何系统管理的其他资源。每个目标都有与之关联的操作和许可权。

  • 操作 operations:对目标进行的特定行为或动作,例如读取、写入、执行、删除等。每个目标都可以定义一组允许的操作,这些操作定义了用户对目标可以执行的行为。

  • 许可权 permissions:基本权限单位,它定义了用户对特定目标执行特定操作的授权。许可权通常由角色来赋予,即角色具有一组许可权,用户通过继承角色的许可权来获得对目标和操作的访问权限。

        管理员首先定义角色并为其分配相应的许可权,然后将角色分配给用户。这样,用户就通过其关联的角色获得了对目标和操作的访问权限。当需要调整用户的权限时,管理员只需修改用户的角色分配,而无需逐个修改用户的许可权,从而大大简化了权限管理过程。

RBAC中对于权限控制的做法

        角色是为了完成各种工作而创造,用户则依据责任和资格来被指派相应的角色,用户可以很容易地从一个角色被指派到另一个角色。

        角色可依新的需求和系统的合并而赋予新的权限,而权限也可根据需要而从某角色中回收。

角色与角色的关系同样也存在继承关系防止越权,角色与角色的关系可以建立起来以囊括更广泛的客观情况。

RBAC设计思想

基本模型RBAC0

        RBAC0定义了能构成RBAC控制系统的最小的元素集合。

        用户和角色、角色和权限多对多关系。

        就是一个用户拥有多个角色,一个角色可以被多个用户拥有,这是用户和角色的多对多关系;同样的,角色和权限也是如此。

角色分层模型RBAC1

        RBAC1建立在RBAC0基础之上,在角色中引入了继承的概念,有了继承那么角色就有了上下级或者等级关系。类似于树形结构,子角色可以继承父角色的所有权限。

        如果采用RBAC0模型做权限系统,我可能需要为经理、主管、专员分别创建一个角色(角色之间权限无继承性),极有可能出现一个问题,由于权限配置错误,主管拥有经理都没有权限。

        RBAC1解决了这个问题,创建完经理角色并配置好权限后,主管角色的权限继承经理角色的权限,并且支持针对性删减主管权限。

角色限制模型RBAC2

        RBAC2在RBAC0基础上加入了约束的概念,主要引入了静态职责分离SSD和动态职责分离DSD。主要是为了增加角色赋予的限制条件,这也符合权限系统的目标:权责明确,系统使用安全、保密。

  1. 角色互斥:同一用户不能分配到一组互斥角色集合中的多个角色,互斥角色是指权限互相制约的两个角色。

    案例:财务系统中一个用户不能同时被指派给会计角色和审计员角色。

  2. 基数约束:一个角色被分配的用户数量受限,它指的是有多少用户能拥有这个角色。

    例如:一个角色专门为公司CEO创建的,那这个角色的数量是有限的。

    先决条件角色:指要想获得较高的权限,要首先拥有低一级的权限。

    例如:先有副总经理权限,才能有总经理权限。

  3. 运行时互斥:例如,允许一个用户具有两个角色的成员资格,但在运行中不可同时激活这两个角色。

统一模型RBAC3

        是RBAC1与RBAC2的合集,所以RBAC3是既有角色分层又有约束的一种模型。这种模式既要维护好角色间的继承关系处理好分层,又要处理角色间的责任分离。

        以上就是RBAC模型的四种设计思想,现在我们用的权限模型都是在RBAC模型的基础上根据自己的业务进行组合和改进。

RBAC 权限管理的在实际系统中的应用

RBAC 权限模型由三大部分构成,即用户管理角色管理权限管理

  • 用户管理按照企业架构或业务线架构来划分,这些结构本身比较清晰,扩展性和可读性都非常好。

  • 角色管理一定要在深入理解业务逻辑后再来设计,一般使用各部门真实的角色作为基础,再根据业务逻辑进行扩展。

  • 权限管理是前两种管理的再加固,做太细容易太碎片,做太粗又不够安全,这里我们需要根据经验和实际情况来设计。

Vben的三种权限处理方式:

  1. 通过用户角色来过滤菜单(前端方式控制),菜单和路由分开配置

  2. 通过用户角色来过滤菜单(前端方式控制),菜单由路由配置自动生成

  3. 通过后台来动态生成路由表(后台方式控制)

前端角色权限

        原理: 在前端写死路由的权限,指定路由有哪些权限可以查看。

  1. 只初始化通用路由,带权限路由没有被加入路由表内。

  2. 在登陆后或其他方式获取用户角色后,通过角色去遍历路由表,获取该角色可以访问的路由表,生成路由表。

  3. 再通过 router.addRoutes 添加到路由实例,实现权限的过滤。

        缺点: 权限相对不自由,如果后台改动角色,前台也要跟着改动。适合角色较固定的系统

动态更换角色

        细粒度权限:函数方式、组件方式、指令方式

后台动态获取

        原理: 通过接口动态生成路由表,且遵循一定的数据结构返回。前端根据需要处理该数据为可识别的结构,再通过 router.addRoutes 添加到路由实例,实现权限的动态生成。

        动态更换菜单:函数方式、组件方式、指令方式

        细粒度权限

vue-router

  vue-router 提供的导航守卫主要用来通过跳转或取消的方式守卫导航。vue-router 提供了导航钩子:全局前置导航钩子 beforeEach 和全局后置导航钩子 afterEach,它们会在路由即将改变前和改变后进行触发。和 beforeEach 不同的是 afterEach 不接收第三个参数 next 函数,也不会改变导航本身。

router.beforeEach((to, from, next) => {
  /* 必须调用 `next` */
})
router.beforeResolve((to, from, next) => {
  /* 必须调用 `next` */
})
router.afterEach((to, from) => {})

导航钩子有3个参数:

  1. to:即将要进入的目标路由对象

  2. from:当前导航即将要离开的路由对象

  3. next :调用该方法后,才能进入下一个钩子函数(afterEach)

// 只有next()是放行,但是如果next()里有参数的话,next()就像被重载一样,就有了不同的功能,实际上是中断当前导航,执行新的导航。
next()//直接进to 所指路由
next(false) //中断当前路由
next('route') //跳转指定路由
next('error') //跳转错误路由

router.addRoute()

router.addRoute 可以动态添加一条新路由。若该路由有 name,并且已经存在一个与之相同的名字,则会覆盖它。

  • 添加一个新的路由记录。

addRoute(route): () => void
  • 添加一个新的路由记录,将其作为一个已有路由的子路由。

addRoute(parentName, route): () => void

router.beforeEach

        全局前置守卫,初始化的时候被调用、每次路由切换之前被调用。A路由向B路由跳转时 只要形成路由跳转,在切换之前进行调用。

  • 添加一个导航钩子,它会在每次导航之前被执行。返回一个用来移除该钩子的函数。

beforeEach(guard): () => void
  • 举个例子:判断token否存在以及要进入的页面。

router.beforeEach((to,from,next)=>{
    let token = localstorage.getItem('token')
    if(to.path=='/login' || token){ // 如果token存在或者要进入的页面是登陆页,放行
        next()
    }else{ // 如果没有token并且进入的页面不是登陆页,那么提示过期并跳转到login页面
    vm.toast('登录过期,请重新登陆')
    setTimeout(() => {
        next({
            path:'/login'
        })
    }, 500);
    }
})

router.afterEach

        全局后置钩子,初始化的时候被调用、每次路由切换之后被调用。

  • 添加一个导航钩子,它会在每次导航之后被执行。返回一个用来移除该钩子的函数。

afterEach(guard): () => void
  • 举个例子:每次切换页面时,页面的title也会跟着修改,同时,让页面滚动到最顶部。

router.afterEach((to,from,nex)=>{
 document.title = to.meta.title
 window.scrollTo(0,0)
})

beforeResolve

        全局解析守卫,在每次导航时都会触发,不同的是,它会在导航被确认之前、所有组件内守卫和异步路由组件被解析之后调用。

  • 添加一个导航守卫,它会在导航将要被解析之前被执行。此时所有组件都已经获取完毕,且其它导航守卫也都已经完成调用。返回一个用来移除该守卫的函数。

beforeResolve(guard): () => void

beforeEnter

路由独享守卫,某一个路由所单独享用的,只有前置没有后置。

const routes = [
  {
    path: '/users/:id',
    component: UserDetails,
    beforeEnter: (to, from) => { //只在进入路由时触发,不会在 params、query 或 hash 改变时触发
      // reject the navigation
      return false
    },
  },
]

beforeRouteEnter

        组件路由守卫,通过路由规则,进入该组件时被调用。

beforeRouteLeave

        组件路由守卫,通过路由规则,离开该组件时被调用(不能说是后置,因为进入之后并不会触发,而是离开这个组件之前会触发)。

const UserDetails = {
  template: `...`,
  beforeRouteEnter(to, from) {
    // 在渲染该组件的对应路由被验证前调用
    // 不能获取组件实例 `this` !
    // 因为当守卫执行时,组件实例还没被创建!
  },
  beforeRouteUpdate(to, from) {
    // 在当前路由改变,但是该组件被复用时调用
    // 举例来说,对于一个带有动态参数的路径 `/users/:id`,在 `/users/1` 和 `/users/2` 之间跳转的时候,
    // 由于会渲染同样的 `UserDetails` 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
    // 因为在这种情况发生的时候,组件已经挂载好了,导航守卫可以访问组件实例 `this`
  },
  beforeRouteLeave(to, from) {
    // 在导航离开渲染该组件的对应路由时调用
    // 与 `beforeRouteUpdate` 一样,它可以访问组件实例 `this`
  },
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值