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

仅资料所有者可更新数据:DRF APIView权限问题求助

解决Django REST Framework中用户可修改他人UserInfo的权限问题

问题根因

你的patch方法直接通过pk查询UserInfo实例后就允许修改,完全没有校验该UserInfo是否属于当前登录用户——这就导致只要知道他人UserInfo的ID,任意登录用户都能篡改其数据。

分步解决方案

1. 新增权限校验逻辑

在patch方法中,获取到UserInfo实例后,必须验证其关联的user是否等于当前请求的request.user,不匹配则返回403权限拒绝。

2. 修复序列化器漏洞

当前序列化器允许修改user字段,恶意用户甚至可以把自己的UserInfo关联到其他用户,需要把user字段设为只读。

3. 异常处理与规范优化

  • 用get_object_or_404替代直接get,避免因无效ID抛出未捕获的异常
  • 修正状态码:PATCH请求成功应返回200 OK(201 CREATED是POST创建资源的标准状态码)
  • 类名遵循PEP8规范(驼峰命名)

4. 可选:优化模型关联(推荐)

从业务逻辑看,一个用户应该对应唯一的UserInfo,建议把ForeignKey改成OneToOneField,更符合实际场景,同时简化查询逻辑。


优化后的完整代码

views.py

from django.shortcuts import get_object_or_404
from rest_framework import status
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework.permissions import IsAuthenticated
from .models import UserInfo
from .serializers import UserInfoSerializers

class GetUserInfo(APIView):
    permission_classes = [IsAuthenticated]

    def get(self, request, format=None):
        # 如果改成OneToOneField,这里可以直接用request.user.userinfo
        userinfos = request.user.userinfo_set.all()
        serializer = UserInfoSerializers(userinfos, many=True)
        return Response(serializer.data)

    def patch(self, request, pk, format=None):
        # 自动处理ID不存在的情况,返回404
        user_info = get_object_or_404(UserInfo, id=pk)
        
        # 核心权限校验:当前用户只能修改自己的UserInfo
        if user_info.user != request.user:
            return Response(
                {"detail": "你没有权限修改此用户信息"},
                status=status.HTTP_403_FORBIDDEN
            )
        
        serializer = UserInfoSerializers(instance=user_info, data=request.data, partial=True)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_200_OK)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

serializers.py

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

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ('id', 'first_name', 'username')

class UserInfoSerializers(serializers.ModelSerializer):
    user = UserSerializer(read_only=True)  # 设置为只读,禁止修改关联用户

    class Meta:
        model = UserInfo
        fields = ('id', 'picture', 'profession', 'user')

models.py(可选优化)

from django.contrib.auth.models import User
from django.db import models

class UserInfo(models.Model):
    # 改成OneToOneField,确保一个用户对应唯一的UserInfo
    user = models.OneToOneField(User, on_delete=models.CASCADE, null=True, related_name='userinfo')
    picture = models.ImageField(upload_to="profile_pics", null=True)
    profession = models.CharField(max_length=200, null=True)

    def __str__(self):
        return f"{self.user}'s Profile Picture"

urls.py(对应类名修改)

from django.urls import path
from rest_framework_simplejwt.views import TokenRefreshView
from . import views

urlpatterns = [
    path('userinfo/', views.GetUserInfo.as_view(), name="UserInfo"),
    path('userinfo/<str:pk>/', views.GetUserInfo.as_view()),
    path('api/token/', views.MyTokenObtainPairView.as_view(), name='token_obtain_pair'),
    path('api/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
    path('register/', views.RegisterView.as_view(), name='auth_register'),
]

内容的提问来源于stack exchange,提问作者Gaurav Joshi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 09:10:31