RBAC是什么?

RBAC  是基于角色的访问控制(Role-Based Access Control )在 RBAC  中,权限与角色相关联,用户通过成为适当角色的成员而得到这些角色的权限。这就极大地简化了权限的管理。这样管理都是层级相互依赖的,权限赋予给角色,而把角色又赋予用户,这样的权限设计很清楚,管理起来很方便。

RBAC  认为授权实际上是Who 、What 、How 三元组之间的关系,也就是Who 对What 进行How 的操作,也就是“主体”对“客体”的操作。

Who:是权限的拥有者或主体(如:User,Role)。

What:是操作或对象(operation,object)。

How:具体的权限(Privilege,正向授权与负向授权)。

然后 RBAC  又分为RBAC0、RBAC1、RBAC2、RBAC3 ,如果你不知道他们有什么区别,你可以百度百科:百度百科-RBAC 估计你看不懂。还是看看我的简单介绍。

我这里结合我的见解,简单的描述下(去掉那么多的废话)。

RBAC0、RBAC1、RBAC2、RBAC3简单介绍。

  • RBAC0:是RBAC的核心思想。
  • RBAC1:是把RBAC的角色分层模型。
  • RBAC2:增加了RBAC的约束模型。
  • RBAC3:其实是RBAC2 + RBAC1。

 

RBAC0,RBAC的核心。

RBAC权限介绍 制作一个简单的rbac组件

RBAC1,基于角色的分层模型

RBAC权限介绍 制作一个简单的rbac组件

RBAC2、是RBAC的约束模型。

RBAC权限介绍 制作一个简单的rbac组件

RBAC3、就是RBAC1+RBAC2

RBAC权限介绍 制作一个简单的rbac组件

估计看完图后,应该稍微清楚一点。

下面来看个Demo。员工权限设计的模型图,以及对应关系。

RBAC权限介绍 制作一个简单的rbac组件

关系图,以及实体设计。

RBAC权限介绍 制作一个简单的rbac组件

表设计

RBAC权限介绍 制作一个简单的rbac组件

在我们平常的权限系统中,想完全遵循  RBAC  模型是很难的,因为难免系统业务上有一些差异化的业务考量,所以在设计之初,不要太理想,太追求严格的  RBAC  模型设计,因为这样会使得你的系统处处鸡肋,无法拓展。

所以在这里要说明一下,  RBAC  是一种模型,是一种思想,是一种核心思想,但是就思想而言,不是要你完全参照,而是你在这个基础之上,融入你自己的思想,赋予你的业务之上,达到适用你的业务。所以要批评一下那些说:“RBAC模型是垃圾,按照它思路去执行,结果无法拓展。”之类话语的人。那是你自己不会变通。

言归正传。

背景需求:

需要在“权限”=>“角色”=>“用户”之间,在赋予一个特殊的角色“客服”,这个需求比较常见,我一个用户想把我的权限分配到“客服”角色上,然后由几个“客服”去操作对应的业务流程。比如我们的天猫,淘宝商家后天就是如此,当店铺开到一定的规模,那么就会有分工。

A客服:负责打单填写发货单。

B~E客服:负责每天对我们说“亲,您好。祝亲生活愉快!”,也就是和我们沟通交流的客服。

F~H:负责售后。

... ...

那么这些客服也是归属到这个商家下面去。而且每个商家可能都有类似的客服,分工完全靠商家自己去分配管理。

RBAC权限介绍 制作一个简单的rbac组件

这样的系统,融合我们的权限控制,关键要看“客服”用户的添加是在哪添加,如果是由客服直接添加,不走我们的统一注册流程,那建议不要融合到上面这一套 权限、角色、用户之间去,而是给用户再多一个绑定,把多个用户绑定到客服下,并且给客服赋予对应的权限。

1、权限赋予:

权限赋予是把当前用户的权限拉出来,然后分配的客服可以小于等于当前用户的权限。

2、权限加载:

正常的加载权限,当用户登录后,并且第一次使用权限判断的时候,  Shiro  会去加载权限。

3、权限判断:

走正常用户权限判断,但是数据操作需要判断是不是当前归属的用户的数据,其实这个是属于业务层,就算你不是客服,也是需要判断。

4、禁用|启用:

禁用启用,也是正常的用户流程,添加到禁用列表里,如果被禁用,就无法操作任何内容。

 

总之:不要让框框架架来限制你的业务,也不要让你的业务局限于框框架架。但是也不推荐你去改动框框架架,而是基于框框架架做业务封装。

 

下面发布一篇基于RBAC3 的设计模型,设计的 Shiro  SpringMVC  Mybatis   Demo  

Demo链接:http://www.sojson.com/shiro

以上摘自:niuli

 

在Django项目中创建一个简单的RBAC权限项目:

  一、根据需求创建不同数量app并在settings中设置,一个用于制作RBAC组件,一个用于在视图当中实现增删改查

  二、设计表结构

from django.db import models

# Create your models here.


class User(models.Model):
    nid = models.AutoField(primary_key=True)
    username = models.CharField(max_length=32, )
    password = models.CharField(max_length=32,)
    roles = models.ManyToManyField(to='Roles')

    def __str__(self):
        return self.username

    class Meta:
        verbose_name = '用户表'


class Roles(models.Model):
    nid = models.AutoField(primary_key=True)
    title = models.CharField(max_length=12, verbose_name='角色名')
    permission = models.ManyToManyField(to='Permission', verbose_name='权限')

    def __str__(self):
        return self.title

    class Meta:
        verbose_name = '角色表'


class Permission(models.Model):
    nid = models.AutoField(primary_key=True)
    title = models.CharField(max_length=12)
    urls = models.CharField(max_length=24)
    
    # action和group用于第二种实现权限校验方式需要添加的字段,不添加这些也能实现
    # 主要作用是在HTML页面当中用模板语言判断是否有权限时,url地址不用写很死
    action = models.CharField(max_length=32, null=True)  # 功能 增删改查
    group = models.ForeignKey(to='PermissionGroup', on_delete=models.CASCADE, null=True)  # 权限分组

    def __str__(self):
        return self.title

    class Meta:
        verbose_name = '权限表'


# 权限分组, 用户分组、角色分组等。用于第二种权限校验方式
class PermissionGroup(models.Model):
    nid = models.AutoField(primary_key=True)
    title = models.CharField(max_length=32)

    def __str__(self):
        return self.title
models.py

  三、登录实现

    1、登录成功后session中需要存放哪些数据结构:

        用户主键ID:用于增删改查操作,判断是否登录等。

        用户名:可以在HTML页面通过模板语言{{request.session.username}}方式获取,用于导航条显示用户名,点击跳转用户界面

        用户权限url:通过列表形式存放

        …………

def reg_session(request, user):
    """
    登录后将权限和用户id存入session,存入后才能进行权限校验
    :param request:
    :param user: 登录对象
    :return: 没有返回值
    """
    request.session['user_id'] = user.pk
    request.session['username'] = user.username
    # 将用户的所有权限url以列表形式添加到session
    permission_urls_obj_list = user.roles.values('permission__urls').distinct()
    permission_urls_list = [permission_urls['permission__urls'] for permission_urls in permission_urls_obj_list]
    request.session['permission_urls_list'] = permission_urls_list

    # 将用户权限分组nid为键(1为用户管理,2为角色管理),action和url为值,以字典形式存入到session,
    #    {1: {
    #         'urls': ['/users/', '/users/add/', '/users/delete/(\\d+)', 'users/edit/(\\d+)'],
    #         'actions': ['list', 'add', 'delete', 'edit']},

    # 第二种校验方式,可以在HTML页面不写死url判断是否有删改的操作,即该不该显示删除、修改或者增加的按钮
    permission_dict = {}
    urls_action_nid = user.roles.values('permission__urls', 'permission__action', 'permission__group__nid').distinct()

    for i in urls_action_nid:
        nid = i['permission__group__nid']
        if nid not in permission_dict:
            permission_dict[nid] = {
                    'urls': [i['permission__urls']],
                    'actions': [i['permission__action']]
                    }
        else:
            permission_dict[nid]['urls'].append(i['permission__urls'])
            permission_dict[nid]['actions'].append(i['permission__action'])

    request.session['permission_dict'] = permission_dict
登录成功后调用该方法,将数据结构存入session,用于中间件获取后进行校验

相关文章: