DRF generics.RetrieveUpdateDestroyAPIView非管理员访问报无权限问题
问题原因
非管理员用户访问被拦截的核心原因是permissions.py中自定义权限类IsUserOrIsAdmin的逻辑和当前Booking接口的业务场景不匹配,和get_queryset方法无关:
- 该权限类的非管理员放行条件为
isinstance(obj, User) and request.user == obj,仅当操作对象是User模型实例、且实例对应当前登录用户时才放行,但你当前视图操作的是Booking模型实例,该判断条件永远不成立 - 最终非管理员用户访问时,仅
request.user.is_staff为True(也就是管理员)的分支能通过校验,其余用户全部被拦截返回权限错误
修复步骤
1. 修正自定义权限类逻辑
适配Booking接口的权限规则,重写IsUserOrIsAdmin类:
from rest_framework.permissions import BasePermission class IsUserOrIsAdmin(BasePermission): """管理员可访问所有预订记录,普通用户仅可访问自己名下的预订记录""" def has_permission(self, request, view): # 校验用户已登录 return bool(request.user and request.user.is_authenticated) def has_object_permission(self, request, view, obj): # 管理员直接放行 if request.user.is_admin: return True # 普通用户仅可操作自身关联的Booking记录 return obj.user == request.user
2. (可选)简化get_queryset写法
你当前的get_queryset逻辑本身没有问题,可以简化为更简洁的写法,不简化也能正常运行:
class BookingRetrtieveUpdateDestroyAPIView(generics.RetrieveUpdateDestroyAPIView): permission_classes = [IsUserOrIsAdmin] serializer_class = BookingSerializer def get_queryset(self): if self.request.user.is_admin: return Booking.objects.all() return Booking.objects.filter(user=self.request.user)
注意:
RetrieveUpdateDestroyAPIView在执行单资源操作时,会先从queryset中取出对应id的对象再做对象权限校验,保留queryset按用户过滤的逻辑可以避免越权遍历id获取其他用户的记录,和权限类形成双重校验,建议保留。
内容的提问来源于stack exchange,提问作者Naveen Pandia
相关产品推荐
相关产品推荐

