You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 03:51:20