Django基于用户角色和client_id实现自定义权限控制的咨询
实现步骤说明
1. 明确权限类的使用场景
你提到的 BasePermission 是Django REST Framework提供的视图层权限校验工具,不需要在模型层使用,直接绑定到对应业务视图上即可,请求进入视图前会自动执行校验逻辑。
2. 先封装通用工具方法
基于你现有的模型结构,先封装两个快速获取用户属性的工具方法,避免后续重复写查询逻辑:
# 可放在项目的utils.py文件中 from .models import UserCustomModel, ClientUser def get_user_role(user): """获取用户角色""" try: return user.usercustommodel.roles except UserCustomModel.DoesNotExist: return None def get_user_client(user): """获取用户所属客户,你现有中间表配置了user为主键,所以每个用户只会有一条有效记录""" try: # 注意你的deleted字段默认值为1代表有效,如果实际是0代表有效请修改判断条件 return ClientUser.objects.get(user=user, deleted=1).client except ClientUser.DoesNotExist: return None
3. 编写符合业务规则的自定义权限类
需要同时实现has_permission(全局访问权限校验)和has_object_permission(单对象操作权限校验)两个方法,覆盖你要求的所有规则:
from rest_framework.permissions import BasePermission class UserManagePermission(BasePermission): # 定义角色层级,数值越大权限越高 ROLE_LEVEL = { 'READER': 1, 'CONTRIBUTOR': 2, 'SUPERUSER': 3, 'ADMIN': 4 } def has_permission(self, request, view): # 先校验当前用户有没有用户管理的全局访问权限 current_role = get_user_role(request.user) return current_role in ['SUPERUSER', 'ADMIN'] def has_object_permission(self, request, view, obj): # obj为当前要操作的目标用户对象 current_user = request.user current_role = get_user_role(current_user) current_client = get_user_client(current_user) target_client = get_user_client(obj) target_role = get_user_role(obj) # 非有效数据直接拒绝 if not all([current_client, target_client, target_role]): return False # 校验同客户限制 if current_client.client_id != target_client.client_id: return False # 校验角色操作权限 if current_role == 'ADMIN': # ADMIN可操作所有权限低于自己的用户 return self.ROLE_LEVEL[target_role] < self.ROLE_LEVEL[current_role] if current_role == 'SUPERUSER': # SUPERUSER仅可操作 CONTRIBUTOR、READER return self.ROLE_LEVEL[target_role] <= 2 return False
4. 在视图层绑定权限类
以DRF的ModelViewSet为例,直接将权限类加到视图的permission_classes属性中即可:
from rest_framework.viewsets import ModelViewSet from django.contrib.auth.models import User from .serializers import UserSerializer class UserManageViewSet(ModelViewSet): queryset = User.objects.all() serializer_class = UserSerializer # 绑定自定义权限类 permission_classes = [UserManagePermission] # 额外补充:列表查询时主动过滤同客户用户,不要依赖权限类做列表过滤 def get_queryset(self): current_client = get_user_client(self.request.user) if not current_client: return User.objects.none() return User.objects.filter( clientuser__client=current_client, clientuser__deleted=1, usercustommodel__deleted=1 )
其他场景适配
如果你用的是Django原生后台而非DRF接口,只需重写对应ModelAdmin的has_add_permission、has_change_permission、has_delete_permission方法,逻辑和上面的权限类完全一致即可。
内容的提问来源于stack exchange,提问作者Anna
相关产品推荐
相关产品推荐

