当前位置: 首页 > 工具软件 > Simple RBAC > 使用案例 >

Django-rest-framework框架之RBAC-基于角色的访问控制,Casbin权限控制,后台管理simplui的介绍和使用

谭伟
2023-12-01

今日内容概要

  • 排序和过滤源码分析
  • 基于jwt的认证类
  • RBAC的介绍和使用
  • Casbin权限控制
  • 后台管理simplui的介绍和使用

排序和过滤源码分析

  • 继承了GenericAPIView+ListModelMixin,只要在视图类中配置filter_backends它就能实现过滤和排序。
    drf内置的过滤类(SearchFilter),排序类(OrderingFiler)
    django-filter
    自定义:写一个类,继承BaseFilterBackend,重写filter_queryset,返回的qs对象,就是过滤或排序后的。
  • 只有获取所有才涉及到排序
    list方法:
   def list(self, request, *args, **kwargs):
   # self.get_queryset()所有数据,经过了self.filter_queryset返回了qs
   # self.filter_queryset完成的过滤
       queryset = self.filter_queryset(self.get_queryset())
			# 如果有分页,走的是分页----》视图类中配置了分页类
       page = self.paginate_queryset(queryset)
       if page is not None:
           serializer = self.get_serializer(page, many=True)
           return self.get_paginated_response(serializer.data)
		  # 如果没有分页,走正常的序列化,返回
       serializer = self.get_serializer(queryset, many=True)
       return Response(serializer.data)
  • self.filter_queryset完成了过滤,当前在视图类中,self是视图类的对象,去视图类中找没找到,去父类中可以找到—》GenericAPIView—》filter_queryset
def filter_queryset(self, queryset):

   for backend in list(self.filter_backends):
       queryset = backend().filter_queryset(self.request, queryset, self)
   return queryset
  • 总结:
    (1)写的过滤类要重写filter_queryset,返回qs(过滤或排序后)对象;
    (2)后期如果不写过滤类,只要在视图类中重写filter_queryset,在里面实现过滤也可以。

基于jwt的认证类

代码展示:

from rest_framework.authentication import BaseAuthentication
import jwt
from rest_framework.exceptions import AuthenticationFailed
from rest_framework_jwt.authentication import JSONWebTokenAuthentication
from rest_framework_jwt.settings import api_settings
from .models import UserInfo

jwt_decode_handler = api_settings.JWT_DECODE_HANDLER

class JWTAuthication(BaseAuthentication):
   def authenticate(self, request):
       # 放到头中:token
       print(request.META)
       jwt_value=request.META.get('HTTP_TOKEN')
       # 验证token是否合法,jwt模块下一定有个验证token的函数
       try:
           payload = jwt_decode_handler(jwt_value)
       except jwt.ExpiredSignature:
           raise AuthenticationFailed('token过期了')
       except jwt.DecodeError:
           raise AuthenticationFailed('解码失败')
       except jwt.InvalidTokenError:
           raise AuthenticationFailed('认证失败')
       # palod可以使用,token合法
       user_id = payload.get('user_id')
       user = UserInfo.objects.filter(pk=user_id).first()

       return user,jwt_value

RBAC的介绍和使用

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

2.RBAC管理模式
RBAC权限管理的模式,最适合公司内部的管理系统,不适合对外互联网用户的系统。

  • 用户:用户表
  • 角色(部门):角色表(部门表)
  • 权限:权限表

所有的权限都是存在权限表中的一条条的记录(发工资,招聘员工,开员工,发布新版本,开董事会)
权限是授予角色的(部门的),一个个角色,就是一条条记录(开发角色,hr角色,股东角色)
用户:一个个用户是用户表中一条条记录,用户属于某个部门

  • 三个表之间的关系:
    (1)用户和角色关系:多对多,要写一个中间表;
    (2)角色和权限关系:多对多,要写一个中间表。
    (3)所以最后得到五张表:用户表;角色表;权限表;用户和角色关联表;角色和权限关联表。

举个栗子:
用户表:

id姓名
1张三
2李四

角色表:

id角色名称
1hr角色
2股东角色
3开发角色

权限表:

id权限名词
1发工资
2招人
3提交代码

需求:张三要有提交代码的权限:
用户和角色中间表:

id角色id用户id
131

权限和角色的中间表:

id角色id权限id
133

django的后台管理admin就自带了rbac的权限,通过auth模块实现,比普通rbac更高级一些;
本来是有5张表,
到django后变成6张表,用户和权限的多对多关系表(一个用户可以分配多个权限,一个权限可以给多个用户)
6张表列举:用户表;角色表;权限表;用户和角色关联表;角色和权限关联表;用户和权限的多对多关系表。
启用了admin和auth,这6张表就迁移进去了。
auth_user # 用户表
auth_group # 角色,组,部门表
auth_permission # 权限表
auth_user_groups # 用户和角色中间表
auth_group_permissions # 角色跟权限中间表
auth_user_user_permissions # 用户和权限的中间表
之前很多公司写后台管理使用django,使用django的admin二次开发,不用写权限了,快速加功能即可。

3.ACL、RBAC、ABAC(PBAC,CBAC)权限控制的介绍

  • ACL(Access Control List,访问控制列表)
    将用户或组等使用者直接与对象的权限对接。
    eg:用户表,权限表,中间表,给用户授予某些权限即可。
  • RBAC(Role-Based Access Control,基于角色的访问控制)
    将用户与角色对接,然后角色与对象的权限对接。
  • RBAC+ACL django,公司用的比较多
  • ABAC(Attribute-Based Access Control,基于属性的访问控制)
    ABAC(Attribute-Based Access Control,基于属性的访问控制)
    又称为PBAC(Policy-Based Access Control,基于策略的访问控制)
    CBAC(Claims-Based Access Control,基于声明的访问控制)

4.三者架构区别

  • 传统的ACL,RBAC的架构是:
    {subject,action,object},
  • ABAC的架构是:
    {subject,action,object,contextual}且为他们添加了parametter(参数)。
    subject属性:比如用户的年龄、部门、角色、威望、积分等主题属性。
    action属性:比如查看、读取、编辑、删除等行为属性。
    object属性:比如银行账户、文章、评论等对象或资源属性。
    contextual属性:比如时段、IP位置、天气等环境属性。

Casbin模块(权限控制)

casbin支持所有的主流权限控制!!!
1.操作步骤
详情可查看https://casbin.org/docs/zh-CN/get-started

  • 新建一个py文件
import casbin

e = casbin.Enforcer("./model.conf", "./policy.csv")

sub = "lqz"  # 想要访问资源的用户
obj = "book"  # 将要被访问的资源
act = "get"  # 用户对资源进行的操作


# 自己写acl的控制
# 当前用户id,去权限和用户表查询即可,有记录就是有权限

# 自己写rbac
# 当前用户id,找到他的角色,根据角色拿出权限,判断当前访问有没有


if e.enforce(sub, obj, act):
   # 允许alice读取data1
   print('有权限')
else:
   # 拒绝请求,抛出异常
   print('没有权限')
  • model.conf
[request_definition]
r = sub, obj, act

[policy_definition]
p = sub, obj, act

[policy_effect]
e = some(where (p.eft == allow))

[matchers]
m = r.sub == p.sub && r.obj == p.obj && r.act == p.act
  • policy.csv
p,alice,data1,read
p,bob,data2,write
p,lqz,book,get

后台管理simplui的介绍和使用

操作流程可参考网址:

https://simple-ui.netlify.app/pc/#%E4%BB%8B%E7%BB%8D

1.提出需求:
django admin自带了权限控制,但是是前后端混合的,我们可以二次开发,开发出公司内部的自动化运行,自动化测试,人事管理系统,订单系统。。。。样子不好看
2.解决方式:
对django admin进行美化

  • xadmin(不用了,过时了)
  • simpleui(正红)

3.使用操作代码书写
settings.py

import time

SIMPLEUI_CONFIG = {
   'system_keep': False,
   'menu_display': ['我的首页', '图书管理','权限认证', '多级菜单测试', '动态菜单测试'],  # 开启排序和过滤功能, 不填此字段为默认排序和全部显示, 空列表[] 为全部不显示.
   'dynamic': True,  # 设置是否开启动态菜单, 默认为False. 如果开启, 则会在每次用户登陆时动态展示菜单内容
   'menus': [
       {
           'name': '我的首页',
           'icon': 'fas fa-code',
           'url': '/index/',

       },
       {
           'app': 'app01',
           'name': '图书管理',
           'icon': 'fas fa-code',
           'models': [
               {
                   'name': '用户',
                   'icon': 'fa fa-user',
                   'url': 'app01/userinfo/'
               },
              {
                   'name': '图书',
                   'icon': 'fa fa-user',
                   'url': 'app01/book/'
               },
               {
                   'name': '出版社',
                   'icon': 'fa fa-user',
                   'url': 'app01/publish/'
               },
           ]
       },
       {
           'app': 'auth',
           'name': '权限认证',
           'icon': 'fas fa-user-shield',
           'models': [{
               'name': '用户',
               'icon': 'fa fa-user',
               'url': 'auth/user/'
           }]
       },
       {
           # 自2021.02.01+ 支持多级菜单,models 为子菜单名
           'name': '多级菜单测试',
          'icon': 'fa fa-file',
          # 二级菜单
           'models': [
               {
                   'name': '百度',
                   'icon': 'far fa-surprise',
                   # 第三级菜单 ,
                   'models': [
                       {
                           'name': '爱奇艺',
                           'url': 'https://www.iqiyi.com/dianshiju/'
                          # 第四级就不支持了,element只支持了3级
                       },
                       {
                         'name': '百度问答',
                           'icon': 'far fa-surprise',
                           'url': 'https://zhidao.baidu.com/'
                       }
                   ]
               },
               {
                   'name': 'lqz',
                   'url': 'https://www.wezoz.com',
                   'icon': 'fab fa-github'
               }]
       },
       {
           'name': '动态菜单测试',
           'icon': 'fa fa-desktop',
           'models': [{
               'name': time.time(),
               'url': 'http://baidu.com',
               'icon': 'far fa-surprise'
           }]
       }]
}


SIMPLEUI_LOGIN_PARTICLES = False
SIMPLEUI_HOME_INFO = False

admin.py

from django.contrib import admin

# Register your models here.

from .models import *


class BookAdmin(admin.ModelAdmin):
   list_display = ('id', 'title', 'price')

   # 增加自定义按钮
   actions = ['make_copy', ]
   def make_copy(self, request, queryset):
       print('adsfasdf')
   make_copy.short_description = '自定义按钮'
   # # icon,参考element-ui icon与https://fontawesome.com
   make_copy.icon = 'fas fa-audio-description'
   # # 指定element-ui的按钮类型,参考>https://element.eleme.cn/#/zh-CN/component/button
   make_copy.type = 'danger'
   make_copy.confirm = '你是否执意要点击这个按钮?'



admin.site.register(UserInfo)
admin.site.register(Publish)
 类似资料: