Django REST Framework打印has_object_permission实例及对象权限实现问题
Django REST Framework 权限问题解答
首先先说明你现有代码中两个直接导致权限失效的问题:
ObjectOwnerPermission的has_object_permission方法逻辑错误:只要用户登录就直接返回True,后续判断对象所有者的代码永远不会执行- 视图中的权限类属性名写错:正确属性名是
permission_classes,你写的permissions_classes多了一个s,导致权限类没有被加载生效
1. 打印has_object_permission排查逻辑的方法
完全可以,你直接在该方法内加入打印语句或者日志输出即可,示例如下:
import logging logger = logging.getLogger(__name__) class ObjectOwnerPermission(BasePermission): message = "仅对象所有者可操作该资源" def has_object_permission(self, request, view, obj): # 打印/输出排查信息 logger.info(f"请求用户: {request.user}, 对象作者: {obj.author}, 请求方法: {request.method}") # 修正后的逻辑:先判断登录,再判断是不是所有者 if not request.user.is_authenticated: return False return obj.author == request.user
启动服务后发起请求,就能在控制台/日志文件中看到对应的参数输出,确认逻辑执行情况。
2. 除权限类外的其他实现方式
有三种常用的实现方案:
- 重写视图的操作方法:直接在
update、destroy方法内做校验,不符合条件直接抛出403异常
示例:from rest_framework.exceptions import PermissionDenied class RetrieveUpdateProjectAPIView(generics.RetrieveUpdateAPIView): queryset = Project.objects.all() serializer_class = serializers.ProjectSerializer def update(self, request, *args, **kwargs): instance = self.get_object() if instance.author != request.user: raise PermissionDenied("仅所有者可修改项目") return super().update(request, *args, **kwargs) - 重写视图的get_object方法:统一处理当前视图所有对象操作的权限校验
示例:def get_object(self): obj = super().get_object() if obj.author != self.request.user: raise PermissionDenied("仅所有者可操作该项目") return obj - 过滤查询集:直接排除非当前用户创建的对象,用户请求其他用户的对象会直接返回404
示例:def get_queryset(self): return Project.objects.filter(author=self.request.user)
3. 基于Serializer校验的实现方法
可以实现,需要利用Serializer的context获取请求对象,在update方法或者validate方法内做校验,示例如下:
from rest_framework import serializers from rest_framework.exceptions import PermissionDenied class ProjectSerializer(serializers.ModelSerializer): # 其他字段定义省略 class Meta: model = Project fields = "__all__" def update(self, instance, validated_data): # 从context中获取请求用户 request = self.context.get("request") if request and instance.author != request.user: raise PermissionDenied("仅所有者可修改项目") return super().update(instance, validated_data)
注意:该方案仅能校验走Serializer更新的请求,删除操作不会经过Serializer的update方法,所以删除场景需要额外处理,建议搭配重写destroy方法使用。
修正后的原始代码参考
class ObjectOwnerPermission(BasePermission): message = "仅对象所有者可操作该资源" def has_object_permission(self, request, view, obj): if not request.user.is_authenticated: return False # 只读请求可以放开权限,需要全权限控制删掉下面这行即可 if request.method in SAFE_METHODS: return True return obj.author == request.user class RetrieveUpdateProjectAPIView(generics.RetrieveUpdateAPIView): # 修正属性名,去掉多余的s permission_classes = [ObjectOwnerPermission] queryset = Project.objects.all() serializer_class = serializers.ProjectSerializer class DeleteProjectAPIView(generics.DestroyAPIView): permission_classes = [ObjectOwnerPermission] queryset = Project.objects.all() serializer_class = serializers.ProjectSerializer
内容的提问来源于stack exchange,提问作者Ahmed Yasin
相关产品推荐
相关产品推荐

