How to hide or change permissions in / api / endpoint in Django Rest?

I would like to disable or set admin rights on / api / endpoint, otherwise no one will be able to view our entire API. However, I don't want to completely remove the django rest UI - I want to prevent people from viewing the list of all endpoints.

There seem to be two possible solutions:

  • Insert a redirect or hide the endpoint somehow
  • Set admin only permissions on endpoint (and only that endpoint - so, only in / api / - not on / api / things /)

I'm wondering if there is a "correct" way to get around this.

+4


source to share


5 answers


You can use permission classes

to set up admin rights checks on the endpoint /api/

.

Lets say MyView

is a presentation class for an endpoint /api/

. In this view, we will set the permission class IsAdminUser

. This will make our API available to admin users only.

For classes:

from rest_framework.permissions import  IsAdminUser

class MyView(..):

    permisssion_classes = (IsAdminUser,) # set the permission class

    .. 

      



For functional views:

@permission_classes((IsAdminUser, )) 
def my_view(..):
    ...

      

This will deny any user that matters user.is_staff

how False

else the permission will be allowed.

+3


source


My approach to this problem may not be the most elegant, but it serves as an example.

urls.py

router = routers.DefaultRouter()
router.register(r'users', views.UserViewSet, base_name='users')
router.register(r'groups', views.GroupViewSet, base_name='groups')
router.register(r'tasks', views.TasksViewSet, base_name='tasks')

urlpatterns = [
    url(r'^$', views.APIRoot.as_view()),
    url(r'', include(router.urls)),
    ...
]

      



views.py

from rest_framework.views import APIView
from rest_framework.response import Response

class APIRoot(APIView):
    """
    API Root ...
    """
    def get(self, request):
        data = {
            "users": "http://localhost:5000/users/",
            "groups": "http://localhost:5000/groups/",
            "tasks": "http://localhost:5000/tasks/",
        }

        if not request.user.is_superuser:
            data.pop("users")
            data.pop("groups")

        return Response(data)

      

+1


source


Rahul's answer is technically correct, but I needed to do something else first.

I originally had:

router.register(r'things', things_viewsets.ThingViewSet)
...
urlpatterns = patterns('',
    url((r'^api/'), include(router.urls)),
    ....
)

      

What I needed to do:

router.register(r'api/things', things_viewsets.ThingViewSet) 
....

urlpatterns += router.urls

      

Then I was able to just remove / api / and have it 404, or I could add auth to it as Rahul explained.

0


source


You should use SimpleRouter()

instead DefaultRouter()

in yoururls.py

https://www.django-rest-framework.org/api-guide/routers/#simplerouter

0


source


The class APIRootView

that defines the view for the root /api/

endpoint has an undocumented private attribute _ignore_model_permissions

set to True

. This attribute is used to ensure that it DjangoModelPermissions

does not apply to the root view because the root view DefaultRouter

does not have an attribute queryset

that is required to work DjangoModelPermissions

.

In short, if you set APIRootView

permissions APIRootView

(for example IsAuthenticated

), then it is safe to set to a _ignore_model_permissions

value False

, which will cause the permission class to be applied to the root view. As an example:

class MyRouter(routers.DefaultRouter):
    def __init__(self, *args, **kwargs):
        self.APIRootView._ignore_model_permissions = False
        self.APIRootView.permission_classes = [IsAuthenticated]
        super().__init__(*args, **kwargs)

      

Please note that we modify self.APIRootView

because DefaultRouter

APIRootView

in an attribute .

Remember, this _ignore_model_permissions

is a private undocumented attribute and therefore there is no guarantee that it will continue to work in the future.

0


source







All Articles