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

我的API出现问题该如何排查修复?附UserViewSet及序列化器代码

让我帮你梳理下这段API代码里可能存在的问题,以及对应的修复方案:

1. IsStaffOrTargetUser权限类大概率有逻辑漏洞

从你写的get_permissions方法来看,非POST请求会用这个权限类,但如果这个类的实现没做对,普通用户可能连自己的账号信息都改不了——比如如果它只判断了用户是不是staff,那普通用户想改个邮箱或者昵称都不行,这显然不符合预期。

怎么修?
你得确保这个权限类正确区分「staff用户能操作所有账号」和「普通用户只能操作自己的账号」,示例代码如下:

from rest_framework.permissions import BasePermission

class IsStaffOrTargetUser(BasePermission):
    def has_permission(self, request, view):
        # 管理员用户拥有所有操作权限
        if request.user.is_staff:
            return True
        # 普通用户只能查看、修改自己的账号,不能删也不能操作别人的
        allowed_actions = ['retrieve', 'update', 'partial_update']
        if view.action not in allowed_actions:
            return False
        # 确认当前操作的对象是用户自己
        return view.get_object() == request.user

2. UserUpdateSerializer可能没限制敏感字段

如果你的更新序列化器是直接继承HyperlinkedModelSerializer,又没处理is_staff、is_superuser这类敏感字段,那普通用户说不定能通过接口把自己改成管理员——哪怕权限类拦着,序列化器没限制的话,提交这些字段就会被更新,这属于权限绕过的漏洞。

怎么修?
把敏感字段设为只读,或者只指定允许用户修改的字段:

from rest_framework import serializers
from django.contrib.auth.models import User

class UserUpdateSerializer(serializers.HyperlinkedModelSerializer):
    # 把管理员相关字段设为只读,不让用户改
    is_staff = serializers.BooleanField(read_only=True)
    is_superuser = serializers.BooleanField(read_only=True)
    date_joined = serializers.DateTimeField(read_only=True)

    class Meta:
        model = User
        # 明确列出用户能修改的字段,比如用户名、邮箱、姓名这些
        fields = ['url', 'username', 'email', 'first_name', 'last_name', 'is_staff', 'is_superuser', 'date_joined']

3. 用户创建接口的两个小坑

你允许未登录用户创建账号,这个逻辑本身没问题,但有两个细节要注意:

  • 第一个是UserCreateSerializer如果允许设置is_staff,那恶意用户能直接创建管理员账号,这太危险了;
  • 第二个是创建用户时一定要用create_user方法,不能直接用User.objects.create——后者会把密码明文存进数据库,完全不符合安全要求。

怎么修?
调整创建序列化器,限制字段+用正确的方法创建用户:

class UserCreateSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = User
        # 只开放必要的创建字段,排除管理员相关的
        fields = ['url', 'username', 'email', 'password', 'first_name', 'last_name']
        # 密码设为只写,不让返回给前端
        extra_kwargs = {'password': {'write_only': True}}

    def create(self, validated_data):
        # 用Django自带的create_user,自动哈希密码
        user = User.objects.create_user(**validated_data)
        return user

4. 额外提醒:删除操作的权限控制

你的视图集用了ModelViewSet,默认包含删除(destroy)操作,但普通用户能不能删自己的账号?如果不想允许,记得在IsStaffOrTargetUser里把destroy排除在允许的action之外——就像我在第一个修复示例里写的那样。


内容的提问来源于stack exchange,提问作者Roman Nozhenko

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 08:31:28