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

drfRBAC

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

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

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



前言

1. drf7表

  • User - 用户表
  • Role - 角色表 (可作为岗位)
  • Group - 分组表 (可作为部门)
  • Permissions - 权限表
  • UserRole - 用户角色多对多中间表
  • UserPermissions - 用户权限多对多中间表
  • RolePermissions - 角色权限多对多中间表
  • 表关联关系如下:

在这里插入图片描述

使用 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
  • PyJWT

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表会 自动生成 10条权限数据(除 管理员权限 外,其余9条来自DEMO,详见代码 TODO 注释,可方便定位DEMO位置)
namecodeName
管理员权限AdminPermission
获取全部用户信息GET_UserPermission
修改全部用户信息PUT_UserPermission
创建全部用户信息POST_UserPermission
删除全部用户信息DELETE_UserPermission
获取特定分组下用户信息GET_GroupUserPermission
修改特定分组下用户信息PUT_GroupUserPermission
创建特定分组下用户信息POST_GroupUserPermission
删除特定分组下用户信息DELETE_GroupUserPermission
获取指定角色用户GET_role_user

2.3. 使用

  • 数据库创建 测试用户 数据
  • 为测试用户分配权限 (UserPermissions 表)
  • 使用 /v1/RBAC/Login/ 接口获取 token 👇

登录请求

  • 请求头中 携带token 即可访问DEMO中提供的路由(需要拥有对应权限,否则会被拦截) 👇

token

urlnamecodeName
/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
  • 为用户分配某一权限,该用户即可用此权限对应的 请求方式 访问该权限对应的 接口
  • e.g.

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

            角色没有 <创建特定分组下用户信息POST_GroupUserPermission> 权限时 ,若对 /v1/RBAC/user/group_user/ 接口进行 POST 请求,则会被拦截



二、推荐的路由层级

示例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表数据:
namecodeName
获取全部用户信息GET_UserPermission
修改全部用户信息PUT_UserPermission
创建全部用户信息POST_UserPermission
删除全部用户信息DELETE_UserPermission
  • 源码位置 APPS.RBAC.apps

3.2.2 自动创建权限类(通用二级权限类)的权限数据生成方式
  • 表字段来源如下:
    • name => f"{请求方式对应的中文}{新action装饰器permission参数中的 字符串}"
    • codeName => f"{请求方式}_{被新action装饰器所装饰方法的 方法名 }"
  • 生成权限数据数量:
    • 手动创建权限类 生成数据不同,通用二级权限类 只会生成 新action装饰器中 methods参数 允许请求方式 所对应的 权限数据
@action(methods=["get"], detail=False, permission="指定角色用户", inherit=True)
def role_user(self, request):
    return Response({
        "code": 200
    })
  • 生成的Permissions表数据:
namecodeName
获取指定角色用户GET_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
  • 7
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 10
    评论
如果每个页面上有多个操作按钮,并且需要根据接口返回的参数进行权限管理,可以封装一个名为"PermissionButton"的组件,该组件接收两个参数:按钮文本和权限标识符。 代码如下: ```html <template> <button v-if="hasPermission" @click="$emit('click')"> {{ buttonText }} </button> </template> <script> export default { props: { buttonText: { type: String, required: true }, permissionIdentifier: { type: String, required: true }, userPermissions: { type: Array, required: true } }, computed: { hasPermission() { return this.userPermissions.includes(this.permissionIdentifier); } } }; </script> ``` 在这个组件中,我们通过props接收了三个参数: - buttonText:按钮文本 - permissionIdentifier:权限标识符 - userPermissions:用户权限 然后,我们在computed属性中定义了一个"hasPermission"计算属性,用来判断当前用户是否拥有该按钮的权限。具体实现是通过判断用户权限中是否包含该按钮的权限标识符。 最后,我们在模板中使用v-if指令判断用户是否拥有该按钮的权限。如果用户拥有权限,就显示按钮,否则不显示。 在每个页面的代码中,我们可以将需要进行权限控制的按钮封装成PermissionButton组件,传递相应的参数。代码示例如下: ```html <template> <div> <permission-button buttonText="添加用户" permissionIdentifier="addUser" :userPermissions="userPermissions" @click="addUser" /> <permission-button buttonText="删除用户" permissionIdentifier="deleteUser" :userPermissions="userPermissions" @click="deleteUser" /> <permission-button buttonText="修改用户" permissionIdentifier="updateUser" :userPermissions="userPermissions" @click="updateUser" /> <!-- 其他需要进行权限控制的按钮 --> </div> </template> <script> import PermissionButton from "@/components/PermissionButton.vue"; export default { components: { PermissionButton }, data() { return { userPermissions: [] }; }, methods: { addUser() { // 添加用户逻辑 }, deleteUser() { // 删除用户逻辑 }, updateUser() { // 修改用户逻辑 } // 其他需要进行权限控制的方法 } }; </script> ``` 在这个代码示例中,我们将多个PermissionButton组件放在了一个div中,分别传递了不同的按钮文本和权限标识符。同时,我们将用户权限传递给了每个PermissionButton组件,并在@click事件中定义了相应的逻辑方法。 这样,我们就可以在多个页面中使用PermissionButton组件,实现对多个操作按钮进行权限控制。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值