如何将 Django Rest Framework 可浏览 API 接口限制为管理员用户

Posted

技术标签:

【中文标题】如何将 Django Rest Framework 可浏览 API 接口限制为管理员用户【英文标题】:How to restrict Django Rest Framework browsable API interface to admin users 【发布时间】:2015-10-09 00:39:44 【问题描述】:

我正在为移动应用开发 Django Rest Framework 后端。 API 是私有的,只能在内部使用。

可浏览的 API 可以方便地帮助开发人员处理项目,但我想防止任何未设置为项目管理员的人使用可浏览界面。

我意识到可浏览的管理员不会授予用户否则不会拥有的任何权限,但它确实有一些安全灰色区域(例如,对于具有外键关系的模型,html 选择器字段会填充所有数据库中可能的相关对象,除非您明确指示不要这样做)。

由于此应用处理敏感的用户数据,我更愿意向公众公开尽可能小的表面积,以减少我自己的潜在错误疏忽的风险。

有什么方法可以为非管理员用户禁用可浏览的 API,而不为所有人禁用它?我已经进行了大量的谷歌搜索并查看了 SO 并没有找到答案。这个问题很接近How to disable admin-style browsable interface of django-rest-framework?,但不一样,因为这些说明会禁用所有人的界面。

【问题讨论】:

如何将 html 选择器字段添加到可浏览的 API?它只是文本输入的 html 表单。 但是,如果你真的认为你需要执行这个禁用,你很可能必须子类化 BrowsableApiRenderer,找到一个很好的地方来挂钩并检查 request.user 的管理员状态,然后渲染没有。不过,我认为这是一个糟糕的解决方案。 github.com/tomchristie/django-rest-framework/blob/master/… 强烈建议在生产环境中删除可浏览的 API(仅在 DEBUGTrue 时将其添加为默认渲染器)。另请注意,如果您的下拉列表暴露了太多信息,那么聪明的人(阅读:其他无聊的开发人员)可能也会链接对象并暴露该数据。 @MarkGalloway 如果您将序列化器字段设置为 PrimaryKeyRelated 等,可浏览的 API 将抛出一个 HTML 选择下拉列表,其中包含所有可能的外键(例如,如果您有系统中的所有用户“用户”外键字段)。这让我感到惊讶,并让我担心可浏览 API 中的信息泄露。 这很酷。我总是声明显式相关的序列化程序,所以我想这就是我从未见过它的原因。 【参考方案1】:

“DEFAULT_PERMISSION_CLASSES”设置不够吗?这对所有视图设置了默认限制DRF docs on default permission classes

settings.py:

REST_FRAMEWORK = 
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.IsAdminUser',
    ]

他们将“到达”可浏览界面,但如果未经授权,所有类型的请求都将被拒绝。

如果出于某种原因,非管理员用户需要访问各种端点,您可以放宽逐个视图的限制。

【讨论】:

这是一个很好的答案。使用 DEBUG=False 这实质上会禁用生产中的可浏览 api。【参考方案2】:

假设您使用的是 DRF 的内置视图,我认为您可以直接覆盖 get_renderers()

在您的设置文件中:

REST_FRAMEWORK = 
    # Only enable JSON renderer by default.
    'DEFAULT_RENDERER_CLASSES': [
        'rest_framework.renderers.JSONRenderer',
    ],

然后在你的views.py:

from rest_framework import generics, renderers

class StaffBrowsableMixin(object):
    def get_renderers(self):
        """
        Add Browsable API renderer if user is staff.
        """
        rends = self.renderer_classes
        if self.request.user and self.request.user.is_staff:
            rends.append(renderers.BrowsableAPIRenderer)
        return [renderer() for renderer in rends]

class CustomListApiView(StaffBrowsableMixin, generics.ListAPIView):
    """
    List view.
    """
    # normal stuff here

【讨论】:

谢谢!帮我解决了我的问题***.com/q/58884611/420953。欢迎您对它作出相同的回答。您将如何对使用 BrowsableAPIRenderer 进行单元测试? 很高兴它帮助了@udo!单元测试不是我的专长.. 最好只问另一个问题:)【参考方案3】:

rest_framework 视图中,我们有一个名为renderes_classes 的属性 通常我们有一个方法get_<something>,就像我们对queryset/get_queryset 一样,但在这种情况下我们没有那个,所以我需要实现一个属性。

from tasks.models import Task
from tasks.serializers import TaskSerializer

from rest_framework.generics import ListAPIView
from rest_framework.permissions import IsAuthenticatedOrReadOnly
from rest_framework.renderers import CoreJSONRenderer


class CustomRendererView:
    permission_classes = (IsAuthenticatedOrReadOnly,)

    @property
    def renderer_classes(self):
        renderers = super(ListTask, self).renderer_classes

        if not self.request.user.is_staff:
            renderers = [CoreJSONRenderer]

        return renderers


class ListTask(CustomRendererView, ListAPIView):
    queryset = Task.objects.all()
    serializer_class = FullTaskSerializer

【讨论】:

以上是关于如何将 Django Rest Framework 可浏览 API 接口限制为管理员用户的主要内容,如果未能解决你的问题,请参考以下文章

如何仅使用 django 作为后端并使用 django-rest-framework 发布

Django - 如何通过 API 端点使用 rest_framework 动态地将多个对象添加到数据库中

如何使用 django-rest-framework 进行社交登录? [关闭]

如何将命名空间 url 添加到 django-rest-framework 路由器视图集

如何使用 Django Rest Framework 将 url 字段添加到序列化程序

如何使用 django-rest-framework 中的序列化器将相似数据合并到自定义字段中?