【问题标题】:Edit permissions for Django Details View for api calls编辑 API 调用的 Django 详细信息视图的权限
【发布时间】:2021-06-18 02:56:45
【问题描述】:

我对 django 非常陌生,目前正在尝试生成对 localhost:8000/stateapi/id 的 api 调用,其中 id 是 json 中单个“状态”对象的 id(如 1、2 等)。 它通过将用户名和密码传递给“get-token”端点,然后使用该令牌调用 stateapi 端点来使用令牌身份验证。

我主要遵循本教程https://scotch.io/tutorials/build-a-rest-api-with-django-a-test-driven-approach-part-2 并不断收到“详细信息”:“您无权执行此操作。”

这里是 CreateView 处理“localhost:8000/stateapi”端点和 DetailsView 处理 localhost:8000/stateapi/id 端点的视图。

class CreateView(generics.ListCreateAPIView):                   
    queryset = State.objects.all()
    serializer_class = StateSerializer
    permission_classes = (permissions.IsAuthenticated,IsOwner)                       
                                                                       
    def perform_create(self, serializer):
        """Save the post data when creating a new State."""
        serializer.save(owner=self.request.user)                   
                                                                   
class DetailsView(generics.RetrieveUpdateDestroyAPIView):        
    """This class handles the http GET, PUT and DELETE requests."""

    queryset = State.objects.all()
    serializer_class = StateSerializer
    permission_classes = (permissions.IsAuthenticated,IsOwner)

我似乎无法弄清楚为什么经过身份验证的用户有权从 CreateView 访问信息,但不能从 DetailsView 访问信息。

这是权限代码:

class IsOwner(BasePermission):
"""Custom permission class to allow only bucketlist owners to edit them."""

def has_object_permission(self, request, view, obj):
    # Our problem is that we do not have a owner property for the object
    """Return True if permission is granted to the bucketlist owner."""
    return obj.owner == request.user

在测试调用 DetailsView 时会发生什么时,我发现调用 DetailsView 时 obj.owner 为“None”,并且每当调用 CreateView 时 obj.owner 正确等于 request.user,这将解释为什么经过身份验证的用户可以向没有 id 的端点发出 get 请求,而不能向有 id 的端点发出请求。

有没有关于我怎么做的建议:

  • a) 确保 obj 具有正确的“所有者”属性(CreateView 正在执行但 DetailsView 未执行的操作)
  • b) 以某种方式更改我的权限
  • c) 其他我想不到的东西。

谢谢!

你能分享你的 State 模型和 StateSerializer – Iain Shelvington 6 月 18 日 3:26

状态模型:

from django.db import models
from django.db.models.signals import post_save
from django.contrib.auth.models import User
from rest_framework.authtoken.models import Token
from django.dispatch import receiver

# Create your models here.
# 1 is /, 2 is -, 3 is (, 4 is ), 5 is .
class State(models.Model):
    STATE                                                   = models.CharField(max_length=30,blank=True,null=True)
    Team_Contact                                            = models.CharField(max_length=100,blank=True,null=True)
    CONTACT_INFORMATION                                     = models.TextField(blank=True,null=True)
    LEGISLATION1EXECUTIVE_ORDER                             = models.TextField(blank=True,null=True)
    TESTING                                                 = models.TextField(blank=True,null=True)
    TESTING1DEPLOYMENT_REQUIREMENTS_3SELF_CERTIFICATION4    = models.TextField(blank=True,null=True)
    PRE2EMPTION                                             = models.TextField(blank=True,null=True)
    owner                                                   = models.ForeignKey('auth.User', related_name='statelists', on_delete=models.CASCADE,blank=True,null=True)                                                  
    OVERSIGHT_DEPARTMENT                                    = models.TextField(blank=True,null=True)
    INFRASTRUCTURE_DEVELOPMENTS                             = models.TextField(blank=True,null=True)
    CRASHES1SAFETY_INCIDENTS                                = models.TextField(blank=True,null=True)
    DATA1PRIVACY_CONCERNS                                   = models.TextField(blank=True,null=True)
    PUBLIC_EDUCATION_FOR_AVS                                = models.TextField(blank=True,null=True)
    LIABILITY1INSURANCE_REQUIREMENTS                        = models.TextField(blank=True,null=True)
    HEALTH1EQUITY_CONCERNS                                  = models.TextField(blank=True,null=True)
    MISC5                                                   = models.TextField(blank=True,null=True)

    def __str__(self):
        """Return a human readable representation of the model instance."""
        return "{}".format(self.STATE)
    
    # This receiver handles token creation immediately a new user is created.
@receiver(post_save, sender=User)
def create_auth_token(sender, instance=None, created=False, **kwargs):
    if created:
        Token.objects.create(user=instance)

序列化器:

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

class StateSerializer(serializers.ModelSerializer):
    """Serializer to map the Model instance into JSON format."""

    # understand exactly what this line does
    owner = serializers.ReadOnlyField(source='owner.username') 

    class Meta:
        """Meta class to map serializer's fields with the model fields."""
        model = State
        fields = ('id','STATE','Team_Contact','CONTACT_INFORMATION','LEGISLATION1EXECUTIVE_ORDER','TESTING',
        'TESTING1DEPLOYMENT_REQUIREMENTS_3SELF_CERTIFICATION4','PRE2EMPTION','OVERSIGHT_DEPARTMENT','INFRASTRUCTURE_DEVELOPMENTS',
        'CRASHES1SAFETY_INCIDENTS','DATA1PRIVACY_CONCERNS','PUBLIC_EDUCATION_FOR_AVS','LIABILITY1INSURANCE_REQUIREMENTS',
        'HEALTH1EQUITY_CONCERNS','MISC5', 'owner')

        read_only_fields = ('STATE', 'Team_Contact','CONTACT_INFORMATION')


class UserSerializer(serializers.ModelSerializer):
    """A user serializer to aid in authentication and authorization."""

    states = serializers.PrimaryKeyRelatedField(
        many=True, queryset=State.objects.all())

    class Meta:
        """Map this serializer to the default django user model."""
        model = User
        fields = ('id', 'username', 'states')

【问题讨论】:

  • 你能分享你的State模型和StateSerializer
  • 当然!我会分享它
  • 这可能是因为所有者的序列化程序有source=owner.username 不确定这是必要的。我想这是一个字符串,而不是您期望的用户名对象。
  • 我删除了它,但 stateapi/1 的权限仍然被拒绝 :(

标签: python django api django-rest-framework


【解决方案1】:

这里的一切似乎都很正常。我认为问题来自您代码的其他部分?还是您检查的对象实际上没有链接到它的任何所有者?

【讨论】:

  • 知道如何确保我检查的对象有与其相关联的所有者吗?我不确定为什么 CreateView 有正确的对象所有者,但 DetailsView 没有。
  • 我的意思是你真的检查过你的对象是用链接的所有者保存的吗?我正在想象一个场景,您只需将所有者属性添加到您的对象而不保存。您可以检查数据库中的记录以进行检查。我是这么认为的^^
  • 您对保存具有链接所有者的对象有何建议?
猜你喜欢
  • 2020-05-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-17
  • 1970-01-01
  • 1970-01-01
  • 2016-04-14
  • 2017-04-26
相关资源
最近更新 更多