Django REST Framework - 如何为非员工用户禁用可浏览的 API (is_staff=False)

udo*_*udo 4 python django django-rest-framework

就我而言,我使用 Django REST Framework (DRF) 作为内部 api。它不适合普通用户使用。因此我想为普通用户禁用它。

管理员 ( is_staff=True) 应该能够访问并查看它:https :
//restframework.herokuapp.com/ 在此处输入图片说明

非员工用户 ( is_staff=False) 应该只获得 GET 请求的 JSON 响应,例如:https :
//restframework.herokuapp.com/?format=json 在此处输入图片说明 他不应该(!)看到可浏览的 api。这适用于根视图和所有端点。

为了配置它,我应用了以下内容:

# settings.py

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': ['rest_framework.authentication.SessionAuthentication'],
    'DEFAULT_PERMISSION_CLASSES': ['rest_framework.permissions.IsAuthenticated'],
}

Run Code Online (Sandbox Code Playgroud)

我的端点如下(为了保持示例简单,我只显示 1):

# api/urls.py
from django.urls import include, path

from rest_framework import routers

from . import views

app_name = 'api'

router = routers.DefaultRouter()  # browseable api
router.register('segments', views.SegmentViewSet)
# there are a lot more...

urlpatterns = [
    path('', include(router.urls)),
]
Run Code Online (Sandbox Code Playgroud)

基于答案/sf/answers/4122593891/settings.py看起来像这样:

# settings.py

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': ['rest_framework.authentication.SessionAuthentication'],
    'DEFAULT_PERMISSION_CLASSES': ['rest_framework.permissions.IsAuthenticated'],
    # enable JSON renderer by default
    'DEFAULT_RENDERER_CLASSES': [
        'rest_framework.renderers.JSONRenderer',
    ],
}
Run Code Online (Sandbox Code Playgroud)

和我的api/views.py

# api/views.py

from django_filters import rest_framework as drf_filters
from rest_framework import filters, renderers, viewsets

from . import serializers
from segment.models import Segment

class StaffBrowsableAPIMixin:
    def get_renderers(self):
        """
        add BrowsableAPIRenderer if user is staff (regular users see JSONRenderer response)
        """
        # explicitly set renderer to JSONRenderer (the default for non staff users)
        rends = [renderers.JSONRenderer]
        if self.request.user.is_staff:
            # staff users see browsable API
            rends.append(renderers.BrowsableAPIRenderer)
        return [renderer() for renderer in rends]

class SegmentViewSet(StaffBrowsableAPIMixin, viewsets.ReadOnlyModelViewSet):
    queryset = Segment.objects.all()
    serializer_class = serializers.SegmentSerializer
Run Code Online (Sandbox Code Playgroud)

这适用于所有端点(当普通用户通过 GET 调用端点时,他们只能看到 JSON,而不是可浏览的 API)。不幸的是,它不适用于APIRootView(api 的根视图,例如https://restframework.herokuapp.com/)。

如何让它也起作用APIRootView

get*_*up8 5

编辑

更好地理解您的问题(我相信),您可以非常简单地锁定 API 的基本 URL(mixin 可能应该移动到另一个文件,但为了清晰起见,只需将所有内容放在一起):

# api/urls.py
from django.urls import include, path

from rest_framework import permissions, renderers, routers

from . import views

app_name = 'api'

class StaffBrowsableAPIMixin:
    def get_renderers(self):
        """
        add BrowsableAPIRenderer if user is staff (regular users see JSONRenderer response)
        """
        # explicitly set renderer to JSONRenderer (the default for non staff users)
        rends = [renderers.JSONRenderer]
        if self.request.user.is_staff:
            # staff users see browsable API
            rends.append(renderers.BrowsableAPIRenderer)
        return [renderer() for renderer in rends]


class CustomAPIRootView(StaffBrowsableAPIMixin, routers.APIRootView):
    permission_classes = (permissions.IsAdminUser,)


class CustomDefaultRouter(routers.DefaultRouter):
    APIRootView = CustomAPIRootView

router = CustomDefaultRouter()  # browseable api
router.register('segments', views.SegmentViewSet)
# there are a lot more...

urlpatterns = [
    path('', include(router.urls)),
]
Run Code Online (Sandbox Code Playgroud)

permission_classes将处理没有表现出对非管理员用户,但可浏览API模板仍然会显示您的任何端点。要删除它,您需要使用StaffBrowsableAPIMixin.


原答案

一种方法是使用 DRF 的渲染器设置和方法。

在您的settings.py

REST_FRAMEWORK = {
    # Only enable JSON renderer by default.
    'DEFAULT_RENDERER_CLASSES': [
        'rest_framework.renderers.JSONRenderer',
    ],
}
Run Code Online (Sandbox Code Playgroud)

而在你的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
Run Code Online (Sandbox Code Playgroud)

基本上,StaffBrowsableMixin用于APIView您希望为员工启用 BrowsableAPI 的任何内容。

类似的问题,如上面评论中的链接,以及我的回答:https : //stackoverflow.com/a/58762483/4599228