我的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
相关产品推荐
相关产品推荐

