django 如何更新DRF中的“Allow”标头以匹配OPTIONS请求的权限?

rmbxnbpk  于 2023-08-08  发布在  Go
关注(0)|答案(1)|浏览(112)

bounty已结束.回答此问题可获得+100声望奖励。赏金宽限期11小时后结束。Denis Rouzaud希望引起更多关注此问题。

我使用的是Django Rest Framework 3.14,带有ModelViewsets和一个设置范围的DjangoModelOrAnonReadOnly权限类。
给定这个配置,我的JSON API似乎以一种误导的方式响应OPTIONS请求,即向/api/collections/collectionA/items发送未经身份验证的OPTIONS请求时,会在标头中回复Allow: GET, POST, HEAD, OPTIONS(正确的是:GET, HEAD, OPTIONS)。但是,如果我定义自己的metadataclass并执行以下操作:

def options(self, request, *args, **kwargs) -> response.Response:
    allowed_actions = self.metadata_class().determine_actions(request, self)
    allowed_actions = ", ".join(allowed_actions.keys())
    # ^ allowed_actions is correct 
    data = self.metadata_class().determine_metadata(request, self)
    return response.Response(data, headers={"Allow": allowed_actions})

字符串
我能够得到正确的allowed_actions(GET,OPTIONS,HEAD)。然而,是我的问题,头文件是未修改的最后一条语句在上面的剪切。
如何更新头文件以确保Allow头文件正确反映API的状态?
上下文:在实现OGC API Features端点时需要此上下文。这是一个OpenAPI对地理空间数据的定义。详细信息可以在here中找到。
第4部分(CRUD操作):
服务器不需要实现本说明书中描述的每个方法(即,POST、PUT、PATCH或DELETE)。此外,支持从集合中添加、修改或移除资源的功能的服务器不太可能是开放式服务器。也就是说,对服务器的访问,特别是允许资源创建、修改和/或移除的操作将被控制。例如,此类控制可能采取政策要求的形式(例如,该服务器上的资源可以被插入或更新但不能被删除)或用户访问控制要求(例如,用户“X”仅被允许创建资源,但不允许更新或删除资源)。不管控件是什么,服务器必须能够在适当的控件上下文中通告它提供的每个资源可用的方法。这是使用HTTP OPTIONS方法完成的。
HTTPOPTIONS方法允许服务器显式声明特定资源端点支持哪些HTTP方法。本规范处理HTTP POST、PUT、PATCH和DELETE方法,但可以为特定资源列出任何相关的HTTP方法。

taor4pac

taor4pac1#

更新-1

看起来你需要覆盖**finalize_response(...)**方法来修补Allow头。

from django.http import Http404
from rest_framework import permissions, viewsets
from rest_framework.exceptions import APIException, PermissionDenied
from rest_framework.request import clone_request

from polls.models import Poll

from .serializers import PollSerializer

def get_allow_list(request, view) -> list[str]:
    allowed_methods = []
    for method in view.allowed_methods:
        view.request = clone_request(request, method)
        try:
            view.check_permissions(view.request)
            allowed_methods.append(method)
        except (APIException, PermissionDenied, Http404):
            pass

    return allowed_methods

class PollViewSet(viewsets.ModelViewSet):
    serializer_class = PollSerializer
    queryset = Poll.objects.all()
    permission_classes = [permissions.DjangoModelPermissionsOrAnonReadOnly]

    def finalize_response(self, request, response, *args, **kwargs):
        response = super().finalize_response(request, response, *args, **kwargs)
        if request.method == "OPTIONS":
            allow_str = ", ".join(get_allow_list(request, self))
            response.headers["Allow"] = allow_str
        return response

字符串
我想你误解了Allow头的概念

**Allow**头部列出了一个资源支持的 * 方法集 *。

由于您使用的是**ModelViewsets**,并且我假设您将其与路由器一起使用,并且具有所有默认配置,因此很可能您将为客户端启用所有HTTP方法。换句话说,Allow头返回的值与 Authorization 检查无关。

相关问题