Django基于RBAC的权限组件

Django基于RBAC的权限组件


RBAC前奏

  1. RBAC概念
    RBAC(Role-Based Access Control,基于角色的访问控制),就是用户通过角色与权限进行关联。简单地说,一个用户拥有若干角色,每一个角色拥有若干权限。这样,就构造成“用户-角色-权限”的授权模型。在这种模型中,用户与角色之间,角色与权限之间,一般者是多对多的关系。

  2. 扩展

    • 角色是什么?可以理解为一定数量的权限的集合,权限的载体。例如:一个论坛系统,“超级管理员”、“版主”都是角色。版主可管理版内的帖子、可管理版内的用户等,这些是权限。要给某个用户授予这些权限,不需要直接将权限授予用户,可将“版主”这个角色赋予该用户。
    • 当用户的数量非常大时,要给系统每个用户逐一授权(授角色),是件非常烦琐的事情。这时,就需要给用户分组,每个用户组内有多个用户。除了可给用户授权外,还可以给用户组授权。这样一来,用户拥有的所有权限,就是用户个人拥有的权限与该用户所在用户组拥有的权限之和。
    • 在应用系统中,权限表现成什么?对功能模块的操作,对上传文件的删改,菜单的访问,甚至页面上某个按钮、某个图片的可见性控制,都可属于权限的范畴。有些权限设计,会把功能操作作为一类,而把文件、菜单、页面元素等作为另一类,这样构成“用户-角色-权限-资源”的授权模型。而在做数据表建模时,可把功能操作和资源统一管理,也就是都直接与权限表进行关联,这样可能更具便捷性和易扩展性。
    • 请留意权限表中有一列“权限类型”,我们根据它的取值来区分是哪一类权限,如“MENU”表示菜单的访问权限、“OPERATION”表示功能模块的操作权限、“FILE”表示文件的修改权限、“ELEMENT”表示页面元素的可见性控制等。
    • 这样设计的好处有二。其一,不需要区分哪些是权限操作,哪些是资源,(实际上,有时候也不好区分,如菜单,把它理解为资源呢还是功能模块权限呢?)。其二,方便扩展,当系统要对新的东西进行权限控制时,我只需要建立一个新的关联表“权限XX关联表”,并确定这类权限的权限类型字符串。
    • 这里要注意的是,权限表与权限菜单关联表、权限菜单关联表与菜单表都是一对一的关系。(文件、页面权限点、功能操作等同理)。也就是每添加一个菜单,就得同时往这三个表中各插入一条记录。这样,可以不需要权限菜单关联表,让权限表与菜单表直接关联,此时,须在权限表中新增一列用来保存菜单的ID,权限表通过“权限类型”和这个ID来区分是种类型下的哪条记录。
    • 随着系统的日益庞大,为了方便管理,可引入角色组对角色进行分类管理,跟用户组不同,角色组不参与授权。例如:某电网系统的权限管理模块中,角色就是挂在区局下,而区局在这里可当作角色组,它不参于权限分配。另外,为方便上面各主表自身的管理与查找,可采用树型结构,如菜单树、功能树等,当然这些可不需要参于权限分配。
  3. 基于rbac的实现
    flask-rbac
    simple-rbac


知识点储备

  1. Django ORM
    常用的orm方法,all,values,values_list等
    from models import User
  • all
    models.User.objects.all(),返回值为queryset类型,形如:[obj,obj,obj]
  • values
    models.User.objects.values(‘id’,’username’,’password’),返回值为queryset类型,形如:[{‘id’:1,’username’:’shuke’,’password’:’123456’}]
  • values_list
    models.User.objects.values_list(‘id’,’username’,’password’),返回值为queryset类型,形如: [(1,’shuke’,’123456’),(2,’mary’,’123456’)]
  1. 一对多及多对多
  • 一对多(FK常用操作)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    from django.db import models
    class A(models.Model):
    name = models.CharField(max_length=32)

    class B(models.Model):
    title = models.CharField(max_length=32)
    fk = models.ForeignKey(to="A")
    # 跨表操作
    a. all()
    b_list = models.B.objects.all()
    for item in b_list:
    item.id
    item.name
    item.fk_id
    item.fk
    item.fk.name
    item.fk.id
    b. values()
    b_list = models.B.objects.values('id','name','fk_id','fk__name')
    for item in b_list:
    item['id']
    item['name']
    item['fk_id']
    item['fk__name']
    c. values_list()
    b_list = models.B.objects.values_list('id','name','fk_id','fk__name')
    for item in b_list:
    item[0] # id
    item[1] # name
    item[2] # fk_id
    item[3] # fk__name
    d. 查找名称是"Jack"的用户所有B表中的数据
    models.B.objects.filter(fk__name="Jack").all()
  • 多对多(ManyToMany)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    from django.db import models
    class A(models.Model):
    name = models.CharField(max_length=32)

    class B(models.Model):
    title = models.CharField(max_length=32)
    m2m = models.ManyToMany(to="A")
    PS: 自动会生成第3张表
    a. 在A和B表中各插入2条数据
    models.A.objects.create(name="Jack")
    models.A.objects.create(name="Mary")

    models.A.objects.create(title="IT")
    models.A.objects.create(title="CTO")

    b. CTO和['Jack','Mary']创建关系
    obj = models.B.objects.get(title="CTO")
    obj.m2m.add(1) # 此处可以写id也可以写关联的A表中的obj
    obj.m2m.add(2)

    c. 查找CTO的关联的人
    obj = models.B.objects.get(title="CTO")
    obj.m2m.all() # 得到一个QuerySet列表,内容为A表中的对象
  1. 中间件
    中间件其实就是一个类,包含2个方法,形如:
    1
    2
    3
    4
    5
    6
    class MiddleWare:
    # 所有的resquest请求都需要经过该方法,且该方法返回值为None时,继续请求下一个中间件
    def process_request(self,request):
    pass
    def process_response(self,request,response):
    pass

注: 中间件编写完成后需要在settings文件中进行注册使用,注册时注意中间件顺序

  1. Session与Cookie的区别
  • 由于HTTP协议是无状态的协议,所以服务端需要记录用户的状态时,就需要用某种机制来识具体的用户,这个机制就是Session.典型的场景比如购物车,当你点击下单按钮时,由于HTTP协议无状态,所以并不知道是哪个用户操作的,所以服务端要为特定的用户创建了特定的Session,用用于标识这个用户,并且跟踪用户,这样才知道购物车里面有几本书。这个Session是保存在服务端的,有一个唯一标识。在服务端保存Session的方法很多,内存、数据库、文件都有。集群的时候也要考虑Session的转移,在大型的网站,一般会有专门的Session服务器集群,用来保存用户会话,这个时候 Session 信息都是放在内存的,使用一些缓存服务比如Memcached之类的来放 Session。
  • 思考一下服务端如何识别特定的客户?这个时候Cookie就登场了。每次HTTP请求的时候,客户端都会发送相应的Cookie信息到服务端。实际上大多数的应用都是用 Cookie 来实现Session跟踪的,第一次创建Session的时候,服务端会在HTTP协议中告诉客户端,需要在 Cookie 里面记录一个Session ID,以后每次请求把这个会话ID发送到服务器,我就知道你是谁了。有人问,如果客户端的浏览器禁用了 Cookie 怎么办?一般这种情况下,会使用一种叫做URL重写的技术来进行会话跟踪,即每次HTTP交互,URL后面都会被附加上一个诸如 sid=xxxxx 这样的参数,服务端据此来识别用户。
  • Cookie其实还可以用在一些方便用户的场景下,设想你某次登陆过一个网站,下次登录的时候不想再次输入账号了,怎么办?这个信息可以写到Cookie里面,访问网站的时候,网站页面的脚本可以读取这个信息,就自动帮你把用户名给填了,能够方便一下用户。这也是Cookie名称的由来,给用户的一点甜头。
  • 总结:Session是在服务端保存的一个数据结构,用来跟踪用户的状态,这个数据可以保存在集群、数据库、文件中;Cookie是客户端保存用户信息的一种机制,用来记录用户的一些信息,也是实现Session的一种方式。
  1. 正则模块re
    re.match()方法
    决定RE是否在字符串刚开始的位置匹配,返回_sre.SRE_Match对象,如果不能匹配返回None。
    注:这个方法并不是完全匹配。当pattern结束时若string还有剩余字符,仍然视为成功。想要完全匹配,可以在表达式末尾加上边界匹配符’$’
    1
    2
    3
    4
    5
    6
    7
    8
    格式:
    re.match(pattern, string, flags=0)

    print(re.match('com','comwww.runcomoob').group())
    print(re.match('com','Comwww.runcomoob',re.I).group())
    执行结果如下:
    com
    com


RBAC实现

开发RBAC流程

  1. 表结构设计
  2. Django Admin录入数据
  3. 用户登陆
    • 获取角色
    • 获取权限
    • 对权限URL进行去重
  4. 生成权限结构信息,写入session中
    {
    1: {
    'urls': ['/userinfo/', '/userinfo/add/', '/userinfo/(\\d+)/delete/', '/userinfo/(\\d+)/change/'],
    'codes': ['list', 'add', 'del', 'edit']
    },
    2: {
    'urls': ['/order/', '/order/add/', '/order/(\\d+)/delete/', '/order/(\\d+)/change/'],
    'codes': ['list', 'add', 'del', 'edit']
    }
    }
  5. 注册中间件
    • 白名单
    • 获取当前访问url: request.path_info
    • session中获取权限,进行权限访问验证
  6. 自动生成菜单功能
    • 采用自定义tag方式实现(inclusion_tag)
    • 作为模板使用{ menu_html request }方式导入html文件中使用
  7. 通过Django Admin后台进行管理及维护工作

Django ORM表结构设计

5个类6张表

  1. 菜单表
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    class Menu(models.Models):
    """
    菜单表
    """
    title = models.CharField(max_length=32,verbose_name='菜单标题')

    # django admin后台显示用
    class Meta:
    verbose_name_plural = "菜单表"
    # 重写__str__方法,实例化后的对象将以字符串的形式展示,但实际是一个obj,所以,请不要相信你的眼睛,必要时使用type(arg)进行验证
    def __str__(self):
    return self.title
  2. 权限组表
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    class Group(models.Model):
    """
    权限组
    """
    caption = models.CharField(max_length=32, verbose_name="组名称")
    menu = models.ForeignKey(to="Menu", default=1, blank=True, verbose_name="关联的菜单")

    class Meta:
    verbose_name_plural = "权限组"

    def __str__(self):
    return self.caption
  3. 权限表
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    class Permission(models.Model):
    """
    权限表
    """
    title = models.CharField(max_length=32, verbose_name="标题")
    url = models.CharField(max_length=128, verbose_name="含正则的URL")
    # menu_gp为null说明是title为菜单项
    menu_gp = models.ForeignKey(to="Permission", null=True, blank=True, verbose_name="默认选中的组内权限ID", related_name="pm")
    code = models.CharField(max_length=16, verbose_name="权限码")
    group = models.ForeignKey(to="Group", blank=True, verbose_name="所属组")

    class Meta:
    verbose_name_plural = "权限表"

    def __str__(self):
    return self.title
  4. 用户表
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    class User(models.Model):
    """
    用户表
    """
    username = models.CharField(max_length=32, verbose_name="用户名")
    password = models.CharField(max_length=64, verbose_name="密码")
    email = models.CharField(max_length=32, verbose_name="邮箱")
    roles = models.ManyToManyField(to="Role", blank=True, verbose_name="用户关联的角色")

    class Meta:
    verbose_name_plural = "用户表"

    def __str__(self):
    return self.username
  5. 角色表
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    class Role(models.Model):
    """
    角色表
    """
    title = models.CharField(max_length=32, verbose_name="角色名称")
    permissions = models.ManyToManyField(to="Permission", blank=True, verbose_name="角色关联的权限")

    class Meta:
    verbose_name_plural = "角色表"

    def __str__(self):
    return self.title
  6. 附加
  • 创建数据库表结构信息
  • 创建超级用户
  • 在admin.py中注册models类
  • 登陆admin管理后台添加数据,进行管理

settings中添加配置项

1
2
3
4
5
6
7
8
9
10
11
在文件末尾添加配置信息

vim projectname/settings.py
# ########################### 权限管理相关 ###########################3
PERMISSION_MENU_KEY = "asdkjalsdf9uajsdf"
PERMISSION_URL_DICT_KEY = "iujmsufnsdflsdkf"

VALID_URL= [
'^/login/',
"^/admin*"
]

初始化权限信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
#cat rbac/service/init_permission.py

from django.conf import settings

def init_permission(request,user):
"""
用户权限信息初始化,获取当前用户所有权限信息,并保存到Session中
此处的request以及user参数均为对象,user为登陆成功时在数据库中查询到的user对象
:param request:
:param user:
:return:
"""
# 去空去重
permission_list = user.roles.filter(permissions__id__isnull=False).values(
'permissions__id',
'permissions__title', # 用户列表
'permissions__url',
'permissions__code',
'permissions__menu_gp_id', # 组内菜单ID,Null表示是菜单
'permissions__group_id', # 权限的组ID
'permissions__group__menu_id', # 当前权限所在组的菜单ID
'permissions__group__menu__title', # 当前权限所在组的菜单名称
).distinct()

# 菜单相关配置,在inclusion_tag中使用
menu_permission_list= []
for item in permission_list:
tpl = {
'id': item['permissions__id'],
'title': item['permissions__title'],
'url': item['permissions__url'],
'menu_gp_id': item['permissions_menu_gp_id'],
'menu_id': item['permissions__group__menu_id'],
'menu_title': item['permissions__group__menu__title']
}
menu_permission_list.append(tpl)
request.session[settings.PERMISSION_MENU_KEY] = menu_permission_list
# 形如
"""
{"url": "/host/","menu_title": "主机管理","title": "主机列表","id": 1,"menu_gp_id": null,"menu_id": 1},
{"url": "/host/add/","menu_title": "主机管理","title": "添加主机","id": 2,"menu_gp_id": 1,"menu_id": 1},
{"url": "/host/(\\d+)/delete/","menu_title": "主机管理","title": "删除主机","id": 3,"menu_gp_id": 1,"menu_id": 1},
{"url": "/host/(\\d+)/change/","menu_title": "主机管理","title": "修改主机","id": 4,"menu_gp_id": 1,"menu_id": 1}
{"url": "/userinfo/","menu_title": "用户管理","title": "用户列表","id": 5,"menu_gp_id": null,"menu_id": 2},
{"url": "/userinfo/add/","menu_title": "用户管理","title": "添加用户","id": 6,"menu_gp_id": 5,"menu_id": 2},
......
"""

# 权限相关,中间件使用
permission_dict = {}
for item in permission_list:
group_id = item['permissions__group_id']
code = item['permissions__code']
url = item['permissions__url']
if group_id in permission_dict:
permission_dict[group_id]['codes'].append(code)
permission_dict[group_id]['urls'].append(url)
else:
permission_dict[group_id] = {"codes": [code, ], "urls": [url, ]}
request.session[settings.PERMISSION_URL_DICT_KEY] = permission_dict
# 形如
"""
{
"1": {
"codes": ["list","add","delete","edit"],
"urls": ["/host/","/host/add/","/host/(\\d+)/delete/","/host/(\\d+)/change/"]
},
"2": {
"codes": ["list","add","delete","change"],
"urls": ["/userinfo/","/userinfo/add/","/userinfo/(\\d+)/delete/","/userinfo/(\\d+)/change/"]
}
}
"""

注: 用户登陆成功后进行初始化权限信息,在处理用户权限时需要进行数据去重

菜单List及权限Dict格式如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# 菜单List request.session[settings.PERMISSION_MENU_KEY]
[
{
"url": "/host/",
"menu_title": "主机管理",
"title": "主机列表",
"id": 1,
"menu_gp_id": null,
"menu_id": 1
},
{
"url": "/host/add/",
"menu_title": "主机管理",
"title": "添加主机",
"id": 2,
"menu_gp_id": 1,
"menu_id": 1
},
{
"url": "/host/(\\d+)/delete/",
"menu_title": "主机管理",
"title": "删除主机",
"id": 3,
"menu_gp_id": 1,
"menu_id": 1
},
{
"url": "/host/(\\d+)/change/",
"menu_title": "主机管理",
"title": "修改主机",
"id": 4,
"menu_gp_id": 1,
"menu_id": 1
},
{
"url": "/userinfo/",
"menu_title": "用户管理",
"title": "用户列表",
"id": 5,
"menu_gp_id": null,
"menu_id": 2
},
{
"url": "/userinfo/add/",
"menu_title": "用户管理",
"title": "添加用户",
"id": 6,
"menu_gp_id": 5,
"menu_id": 2
},
{
"url": "/userinfo/(\\d+)/delete/",
"menu_title": "用户管理",
"title": "删除用户",
"id": 7,
"menu_gp_id": 5,
"menu_id": 2
},
{
"url": "/userinfo/(\\d+)/change/",
"menu_title": "用户管理",
"title": "修改用户",
"id": 8,
"menu_gp_id": 5,
"menu_id": 2
}
]

# 权限Dict request.session[settings.PERMISSION_URL_DICT_KEY]
{
"1": {
"codes": [
"list",
"add",
"delete",
"edit"
],
"urls": [
"/host/",
"/host/add/",
"/host/(\\d+)/delete/",
"/host/(\\d+)/change/"
]
},
"2": {
"codes": [
"list",
"add",
"delete",
"change"
],
"urls": [
"/userinfo/",
"/userinfo/add/",
"/userinfo/(\\d+)/delete/",
"/userinfo/(\\d+)/change/"
]
}
}

中间件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
cat rbac/middleware/rbac.py

from django.shortcuts import redirect,HttpResponse
from django.conf import settings

# 在后续版本中可能会被废弃,故在此直接引入
#from django.utils.deprecation import MiddlewareMixin
class MiddlewareMixin(object):
def __init__(self, get_response=None):
self.get_response = get_response
super(MiddlewareMixin, self).__init__()

def __call__(self, request):
response = None
if hasattr(self, 'process_request'):
response = self.process_request(request)
if not response:
response = self.get_response(request)
if hasattr(self, 'process_response'):
response = self.process_response(request, response)
return response

class RbacMiddleware(MiddlewareMixin):
def process_request(self,request):
# 1. 当前请求URL
current_request_url = request.path_info

# 2. 处理白名单,如login及admin页面需开放访问权限,根据实际情况而定
for url in settings.VALID_URL_LIST:
if re.match(url,current_request_url):
return None

# 3. 获取session中保存的权限信息
permission_dict = request.session.get(settings.PERMISSION_MENU_LIST)
if not permission_dict:
# 登陆页面
return redirect(settings.RBAC_LOGIN_URL)

flag = False
for group_id, values in permission_dict.items():
for url in values['urls']:
regex = settings.URL_FORMAT.format(url)
if re.match(regex, current_request_url):
flag = True
break
if flag:
break
if not flag:
# 无权访问页面,可以直接redirect
return HttpResponse('无权访问')

自动生成菜单template tags

  1. template tags部分
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    #! /usr/bin/env python
    # -*- coding: utf-8 -*-
    # __author__ = "shuke"
    # Date: 2017/11/20

    from django.conf import settings
    from django.template import Library
    import re
    import json

    register = Library()


    @register.inclusion_tag('menu.html')
    def menu_html(request):
    """
    获取session中的菜单信息,匹配当前URL,生成菜单
    :param request: 请求的requst对象
    :return:
    """
    menu_list = request.session.get(settings.PERMISSION_MENU_KEY)
    # 当前请求URL
    current_url = request.path_info

    menu_dict = {}
    # menu_gp_id为空则是菜单
    for item in menu_list:
    if not item['menu_gp_id']:
    menu_dict[item['id']] = item

    for item in menu_list:
    regax = "^{0}$".format(item['url'])
    if re.match(regax, current_url):
    menu_gp_id = item['menu_gp_id']
    if menu_gp_id:
    menu_dict[menu_gp_id]['active'] = True
    else:
    menu_dict[item['id']]['active'] = True

    result = {}
    for item in menu_dict.values():
    active = item.get('active')
    menu_id = item['menu_id']
    if menu_id in result:
    result[menu_id]['children'].append({'title': item['title'], 'url': item['url'], 'active': active})
    if active:
    result[menu_id]['active'] = True
    else:
    result[menu_id] = {
    'menu_id': item['menu_id'],
    'menu_title': item['menu_title'],
    'active': active,
    'children': [
    {'title': item['title'], 'url': item['url'], 'active': active}
    ]
    }
    print(json.dumps(result, indent=4, ensure_ascii=False))
    return {'menu_dict': result}
  2. 生成的菜单树格式如下
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    {
    "1": {
    "children": [
    {
    "url": "/host/",
    "active": null,
    "title": "主机列表"
    }
    ],
    "menu_id": 1,
    "menu_title": "主机管理",
    "active": null
    },
    "2": {
    "children": [
    {
    "url": "/userinfo/",
    "active": null,
    "title": "用户列表"
    }
    ],
    "menu_id": 2,
    "menu_title": "用户管理",
    "active": null
    }
    }
  3. menu_tpl.html部分
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    {% for k,item in menu_dict.items %}
    <div class="item">
    <div class="item-title"> {{ item.menu_title }} </div>
    {% if item.active %}
    <div class="item-permission">
    {% else %}
    <div class="item-permission hide">
    {% endif %}

    {% for v in item.children %}
    {% if v.active %}
    <a href="{{ v.url }}" class="active">{{ v.title }}</a>
    {% else %}
    <a href="{{ v.url }}">{{ v.title }}</a>
    {% endif %}
    {% endfor %}
    </div>
    </div>
    {% endfor %}
  4. HTML部分使用tags
    1
    2
    3
    # 上文中的menu_html函数依赖request参数,此处需要传入
    { load rbac }
    { menu_html request }

注: 自定义tags只支持传入1个参数

注册中间件使用

project/settings.py

1
2
3
4
5
6
7
8
9
10
11
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'rbac.middleware.rbac.RbacMiddleware',

]

维护

在Django Admin中维护rbac的权限系统并使用

总结

至此,基于role实现的rbac组件基本开发完成,在Django中作为app引入在settings文件中注册后就可以生效使用了,engoy it!

本文标题:Django基于RBAC的权限组件

文章作者:shuke

发布时间:2020年04月20日 - 14:04

最后更新:2020年04月20日 - 14:04

原始链接:https://shuke163.github.io/2020/04/20/Django%E5%9F%BA%E4%BA%8ERBAC%E7%9A%84%E6%9D%83%E9%99%90%E7%BB%84%E4%BB%B6/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

-------------本文结束感谢您的阅读-------------

本文标题:Django基于RBAC的权限组件

文章作者:shuke

发布时间:2020年04月20日 - 14:04

最后更新:2020年04月20日 - 14:04

原始链接:https://shuke163.github.io/2020/04/20/Django%E5%9F%BA%E4%BA%8ERBAC%E7%9A%84%E6%9D%83%E9%99%90%E7%BB%84%E4%BB%B6/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

0%