基于Django REST framework的 接口级别权限 角色访问控制 (使用RBAC7表 / 可自动生成权限数据 / 可自动进行权限校验)

drfRBAC

基于Django REST framework的 接口级别权限 角色访问控制

github地址 👇
https://github.com/WR-han/drfRBAC
期待大佬点星 🤞

  • 自动权限类生成
  • 自动权限表数据生成
  • 自动权限校验
  • 只需着重于权限的分配

目录


前言

1. drf7表

  • User - 用户表
  • Role - 角色表 (可作为岗位)
  • Group - 分组表 (可作为部门)
  • Permissions - 权限表
  • UserRole - 用户角色多对多中间表
  • UserPermissions - 用户权限多对多中间表
  • RolePermissions - 角色权限多对多中间表
  • 表关联关系如下:
基于Django REST framework的 接口级别权限 角色访问控制 (使用RBAC7表 / 可自动生成权限数据 / 可自动进行权限校验)

使用 db_constraint=False 无物理外键

2. 鸭子角色

“ 如果一个角色有些像鸭子、且有和鸭子一样游泳的权限、和鸭子一样叫的权限、和鸭子一样的所有权限,那么这个角色就是鸭子。”

  • 角色(Role)在访问控制逻辑中不参与任何逻辑判断,只作为有同类权限用户的合集,方便同角色用户的权限继承
    • e.g.

              客服角色拥有<访问查看客户接口>的权限

              那么所有角色为客服的用户 就都继承有<访问查看客户接口>的权限

              如果用户本身拥有<访问查看客户接口>的权限,那么当前用户在访问控制逻辑中就可以视为客服

  • 只适用于 访问控制逻辑 不适用于 业务逻辑, 如接口内容为查看 角色为客服的所有用户 ,则无法获取到 拥有与客服完全相同权限 用户的数据
  • 权限(Permission)为访问控制的 唯一核心 ,无论什么身份,只要用户拥有接口所需的权限,即可访问该接口,否则 访问会被拦截
  • 用户(User)可通过计算属性 get_permissions 来获取由自己的权限 (UserRole) 和继承自角色(Role)的权限 (RolePermissions) 组成的列表

3. 用户认证(authentication)

  • * 进行访问控制前 必须 进行 用户认证,案例详见 Module_Auth.Authentications.RBAC_Authentications => DEMO
  • 使用 drf原生authentication ,用法不过多赘述,若不进行用户认证,则 无法 进行 权限自动验证

4. 接口级别权限

  • 所有 接口 如果需要进行访问控制,都可以 / 应该 进行权限判断 (权限类可使用 新的action装饰器 快速创建,并自动生成对应数据,无需 反复手动创建drf权限类)

5. 权限自动验证机制

  1. 当接口 手动 / 自动 配置 权限类 后,便会在 Permission表自动生成 对应该接口的 4条 权限数据 (分别为允许 GET/PUT/POST/DELETE 四种方式请求此接口的权限)
  2. 当用户访问此接口时(已通过drf的 authentication 验证的前提下),若该用户拥有 1.中生成 且与当前 请求方式对应 的权限(UserPermissions表),则可以访问该接口,否则 访问会被拦截

一、快速使用

1. 依赖/包

  • django 2.2
  • MySQL 8
  • Django REST framework
  • pymsql

2. 准备

2.1. 创建key文件

  • Module_Key 下创建 key.py 文件 内容如下:
""" 修改token盐 数据库链接信息 抽离 settings.secret_key,settings.allowed_hosts """ RBAC_token_salt = ""  project_database = {     "default": {         "ENGINE": "django.db.backends.mysql",         "NAME": "",         "USER": "root",         "PASSWORD": "",         "HOST": "127.0.0.1",         "PORT": "3306"     } } project_secret_key = '' project_allowed_hosts = [] 

2.2. 数据库同步

  • migrate并运行项目
  • permissions表会 自动生成 13条权限数据(除管理员权限外,其余12条来自DEMO 详见TODO注释,可方便定位DEMO位置)
name codeName
管理员权限 AdminPermission
获取全部用户基于Django REST framework的 接口级别权限 角色访问控制 (使用RBAC7表 / 可自动生成权限数据 / 可自动进行权限校验)
  • 请求头中 携带token 即可访问DEMO中提供的路由(需要拥有对应权限,否则会被拦截) 👇
基于Django REST framework的 接口级别权限 角色访问控制 (使用RBAC7表 / 可自动生成权限数据 / 可自动进行权限校验)
  • DEMO提供 3个 案例路由,对应所需权限如下表(每个路由对应 增删改查 四种权限):
url name codeName
/v1/RBAC/user/ 获取全部用户信息 GET_UserPermission
修改全部用户信息 PUT_UserPermission
创建全部用户信息 POST_UserPermission
删除全部用户信息 DELETE_UserPermission
/v1/RBAC/user/group_user/ 获取特定分组下用户信息 GET_GroupUserPermission
修改特定分组下用户信息 PUT_GroupUserPermission
创建特定分组下用户信息 POST_GroupUserPermission
删除特定分组下用户信息 DELETE_GroupUserPermission
/v1/RBAC/user/role_user/ 获取指定角色用户 GET_role_user
修改指定角色用户 PUT_role_user
创建指定角色用户 POST_role_user
删除指定角色用户 DELETE_role_user
  • 为用户分配某一权限,该用户即可用此权限对应的 请求方式 访问该权限对应的 接口
  • e.g.

            角色拥有 <获取全部用户信息GET_UserPermission> 权限时 ,即可对 /v1/RBAC/user/ 接口进行 GET 请求

            角色没有 <创建指定角色用户POST_role_user> 权限时 ,若对 /v1/RBAC/user/role_user/ 接口进行 PUT 请求,则会被拦截


二、推荐的路由层级

示例1:www.wrhan.cn/v1/RBAC/user/

示例2:www.wrhan.cn/v1/RBAC/user/role_user/

示例3:www.wrhan.cn/v1/RBAC/group_user/role_user/

  • 路由对应的 含义 👇:

示例1:域名/版本号/模块名/所有用户/

示例2:域名/版本号/模块名/所有用户/指定为某一种角色的用户/

示例3:域名/版本号/模块名/某一分组的所有用户/指定为某一种角色的用户/

  • 路由对应的 数据 👇:

示例1:域名/版本号/模块名/针对某张表的数据/

示例2:域名/版本号/模块名/针对某张表的数据/此表数据中的细分数据/

示例3:域名/版本号/模块名/针对某张表某个顶级分类的数据/此分类数据中的细分数据/

  • 路由对应的 生成 👇:

示例1:域名/版本号/模块名/基于ModelViewSet的自动路由/

示例2:域名/版本号/模块名/基于ModelViewSet的自动路由/action生成的自动路由/

示例3:域名/版本号/模块名/基于ModelViewSet的自动路由/action生成的自动路由/

  • 路由对应的 权限 👇:

示例1:域名/版本号/模块名/一级权限/

示例2:域名/版本号/模块名/一级权限/二级权限/

示例3:域名/版本号/模块名/一级权限/二级权限/


三、权限详解

1. 基础权限类

基础权限类分为两种,均继承自 drf BasePermission类, 仅供 自定义权限类 继承使用

  • MainPermission
    • 位置Module_Custom.Custom_Permission => MainPermission
  • SecondaryPermission
    • 位置Module_Custom.Custom_Permission => SecondaryPermission

2. 自定义权限类(主要使用)

请配置于 Module_Auth.Permissions 中(其中已有DEMO RBAC_Permissions.py

权限类 必须要写 注释 具体原因请查看 👇3. 权限表数据生成

Module_Auth.Permissions 下所有模块中的类,都会在 Permissions表 中自动生成权限数据

  • 具体生成格式请查看 👇3. 权限表数据生成
  • 请确保 Module_Auth.Permissions 下所有模块中的类,都继承自基础权限类(MainPermission /SecondaryPermission ),以免产生无效权限表数据

2.1 一级权限类

所有继承自 MainPermission类 的权限类皆为 一级权限类

  • 创建方法
    • 直接继承 MainPermission类 ,如无需重写drf权限类的 has_permission 方法,内部直接 pass 即可
    • 必须要写注释 ,注释内容为此权限的 释义 ,用作权限数据生成,具体请查看 👇3. 权限表数据生成
class UserPermission(MainPermission):     """     全部用户信息     """     ... 
  • 使用方法
    • 一级权限类与drf原有权限类使用方法相同,配置于 permission_classes 之中
    • 一级权限往往表示对 整个视图集所有自动路由接口 的权限控制
class Users(ModelViewSet):     """一级权限认证 ↓"""      permission_classes = [UserPermission]      authentication_classes = [UserAuthentication]     queryset = User.objects.all()     serializer_class = UserSerializer 

2.2 二级权限类

所有继承自 SecondaryPermission类 的权限类皆为 一级权限类

2.2.1 普通二级权限类

  • 创建方法
    • 直接继承 SecondaryPermission类 ,如无需重写drf权限类的 has_permission 方法,内部直接 pass 即可
    • 必须要写 注释 ,注释内容为此权限的 释义 ,用作权限数据生成,具体请查看 👇3. 权限表数据生成
class GroupUserPermission(SecondaryPermission):     """     特定分组下用户信息     """     ... 
  • 使用方法
    • 普通二级权限类 不能 配置于 permission_classes 之中
    • 普通二级权限类需配置于 新action装饰器permission参数 中,具体请查看 👇4. 新action装饰器
    • 二级权限往往表示对 视图集中某个action自动路由接口 的权限控制
    @action(methods=["get"], detail=False, permission=GroupUserPermission, inherit=False)     def group_user(self, request):         return Response({             "code": 200         }) 

2.2.2 通用二级权限类(常用)

  • 无需手动创建
  • 使用方法
    • 字符串类型 实参传入 新action装饰器permission参数 中即可,此参数作为该权限的 释义
      • 新action装饰器 会在内部自动生成一个 通用二级权限类 并进行配置
      • 通用二级权限类 的类名为 被装饰方法方法名
    @action(methods=["get"], detail=False, permission="指定角色用户", inherit=True)     def role_user(self, request):         return Response({             "code": 200         }) 

👆上述DEMO 会自动生成一个通用二级权限类,其功能 / 自动生成的权限表数据,和下述👇 普通二级权限类 相同

"""伪代码""" class role_user(SecondaryPermission):     """     指定角色用户     """     ... 

2.2.3 普通 / 通用二级权限类的选择

通常情况 下使用 通用二级权限类 即可,更加方便快捷,只需在action装饰器中传入 释义字符串,无需手动创建权限类

  • 而以下情况则需要 手动创建 普通二级权限类:
    • 需要重写权限类的 has_permission 方法
    • 多个二级权限接口 需使用 同一个二级权限 (多个action装饰器 的permission参数传入 同一个 普通二级权限类)
      • 👆此类需求较为常见

2.3 一 / 二级权限类的使用关系

一 / 二级权限类皆可 单独使用 (只配置一级权限或二级权限)

同时使用时的验证先后顺序请查看 👇4.2 inherit参数

3. 权限表数据生成

3.1 生成数量与主要字段

每一个权限类,会自动生成 四条 权限数据,分别对应四种请求方式 如 UserPermission 权限会生成以下四种权限数据(具体请查看 👇3.2 自动生成方式

  • GET: GET_UserPermission
  • PUT: PUT_UserPermission
  • POST: POST_UserPermission
  • DELETE: DELETE_UserPermission

权限表数据拥有两个主要字段:namecodeName

  • name: 权限的名称,即 释义
  • codeName: 权限的代码,往往由 请求方式_权限类名 组成,供 权限验证 时使用

3.2 自动生成方式

自动生成来源有两种:

  • 手动创建于 Module_Auth.Permissions 中的权限类,包括 一级权限类普通二级权限类
  • 新action装饰器 中自动生成的通用二级权限类

3.2.1 手动创建权限类(一级权限类 / 普通二级权限类)的权限数据生成方式

  • 表字段来源如下:
    • name => f"{请求方式对应的中文}{当前类的注释内容}"
    • codeName => f"{请求方式}_{当前类名}"
class UserPermission(MainPermission):     """     全部用户信息     """     ... 
  • 生成的Permissions表数据:
name codeName
获取全部用户信息 GET_UserPermission
修改全部用户信息 PUT_UserPermission
创建全部用户信息 POST_UserPermission
删除全部用户信息 DELETE_UserPermission
  • 源码位置 APPS.RBAC.apps

3.2.2 自动创建权限类(通用二级权限类)的权限数据生成方式

  • 表字段来源如下:
    • name => f"{请求方式对应的中文}{新action装饰器permission参数中的 字符串}"
    • codeName => f"{请求方式}_{被新action装饰器所装饰方法的 方法名 }"
@action(methods=["get"], detail=False, permission="指定角色用户", inherit=True) def role_user(self, request):     return Response({         "code": 200     }) 
  • 生成的Permissions表数据:
name codeName
获取指定角色用户 GET_role_user
修改指定角色用户 PUT_role_user
创建指定角色用户 POST_role_user
删除指定角色用户 DELETE_role_user
  • 源码位置 Module_Custom.Custom_Permission.action

4. 新action装饰器(主要使用)

内置二级权限认证,新增两个参数:permissioninherit

4.1 permission参数

是否需要进行二级权限认证

  • 参数类型:二级权限类(class) / 释义 (str)
    • 当参数为 二级权限类 时,直接进行权限验证
    • 当参数为 释义 时,会先根据释义自动生成通用 二级权限类 ,再进行权限验证
  • 参数默认值:None

4.2 inherit参数

是否继承一级权限(permission_classes中的权限类)的 认证结果

  • 参数类型:bool
    • 当参数为 True 时,表示继承 (等同于一二级权 限验证结果 关系):
      • 一级权限通过无需进行 二级权限验证
      • 一级权限未通过没有设置一级权限 时, 再进行 二级权限验证
    • 当参数为 Fales 时,表示不继承:
  • 参数默认值:True