DRF generics APIView自定义权限不生效问题
问题根源
你的权限不生效有两个核心原因,和models.py无关,问题出在权限类逻辑和视图的queryset处理上:
- 权限类
has_permission方法逻辑完全错误
你写的return request.user or request.user.is_staff用了短路逻辑,只要用户处于登录状态(request.user为认证后的用户实例,布尔值为True),就会直接返回放行结果,后面的管理员判断根本不会执行,等于所有登录用户都能通过接口权限校验。 - DRF默认不会在列表请求时触发对象级权限校验
你写的has_object_permission只在单条对象操作(查询/更新/删除单个用户)时才会被DRF调用,也就是访问/users/<id>/这类接口时才会生效。列表接口(/users/的GET请求)是直接返回整个queryset的序列化结果,不会遍历每条记录调用对象权限校验,所以哪怕你权限类写对了,普通用户访问列表还是能拿到全量数据。
修复方案
1. 修正权限类逻辑
修改permissions.py,先保证只有登录用户能访问接口,对象级权限保持你原来的判断逻辑即可:
from rest_framework.permissions import BasePermission class IsStaffOrTargetUser(BasePermission): def has_permission(self, request, view): # 仅放行已登录的用户 return bool(request.user and request.user.is_authenticated) def has_object_permission(self, request, view, obj): # 单条操作时,管理员可访问所有,普通用户仅能访问自身数据 return request.user.is_staff or obj == request.user
2. 重写视图的get_queryset方法过滤返回结果
不要直接在视图里写死queryset = User.objects.all(),通过重写get_queryset根据用户身份返回对应范围的数据,从数据源层面限制普通用户能访问到的内容:
from rest_framework import generics from .models import User from .serializers import UserSerializer from .permissions import IsStaffOrTargetUser class UserListCreateAPIView(generics.ListCreateAPIView): permission_classes = [IsStaffOrTargetUser] serializer_class = UserSerializer def get_queryset(self): # 管理员返回全量用户,普通用户仅返回自身记录 if self.request.user.is_staff: return User.objects.all() return User.objects.filter(id=self.request.user.id) # 注意你原来的类名拼写错误:Retrtieve → Retrieve,不影响运行但建议修正 class UserRetrieveUpdateDestroyAPIView(generics.RetrieveUpdateDestroyAPIView): permission_classes = [IsStaffOrTargetUser] serializer_class = UserSerializer def get_queryset(self): # 单条接口同样加过滤,避免普通用户通过篡改ID访问他人信息 if self.request.user.is_staff: return User.objects.all() return User.objects.filter(id=self.request.user.id)
验证说明
- 你的models.py逻辑没有问题,自定义的
is_staff属性返回is_admin值的写法符合预期,不需要修改 - 修复后普通用户访问用户列表接口,仅能拿到自己的用户信息;手动输入其他用户ID访问单条接口会返回404,不会泄露其他用户存在的信息
- 管理员账号访问两类接口都能拿到全量用户数据,符合你的权限规则
内容的提问来源于stack exchange,提问作者Naveen Pandia
相关产品推荐
相关产品推荐

