Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

I'd like to disable or set admin permissions on the /api/ endpoint - otherwise anybody can view our entire API. However, I don't want to remove the django rest UI entirely - I only want to stop people from being able to view the list of all the endpoints.

It seems like the two possible solutions are:

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

I'm wondering if there's a "proper" way of going about this.

like image 776
silentwinter Avatar asked Aug 03 '15 16:08

silentwinter


People also ask

How can you secure the Django REST framework based REST API?

User token endpoint The Django rest framework comes with an endpoint that users can use to generate their authentication tokens by providing their valid username and password. In the django_todo project directory add the API endpoint for token generation in the urls.py file.

How do I add permissions in Django?

Add Permissions to a Group If you are using AbstractUser in Django, you must add AUTH_USER_MODEL = 'YourAppName. YourClassName' . This way, you are telling Django to use our custom user model instead of the default one. The code below should go in your admin.py file so that you can see your user model.

What is permissions Safe_methods?

The IsAuthenticatedOrReadOnly permission class allows unauthorized users to perform safe methods, whereas authenticated users can perform any operations. This class is useful when we need to set read permissions for anonymous users and read/write permissions for authenticated users.

Does Django have view permissions?

The Django admin site uses permissions as follows: Access to view objects is limited to users with the “view” or “change” permission for that type of object. Access to view the “add” form and add an object is limited to users with the “add” permission for that type of object.


3 Answers

You can use permission classes to set admin user permission checks on /api/ endpoint.

Lets say, MyView is the view class for the /api/ endpoint. We will set IsAdminUser permission class on this view. This will make our API to be accessible to only admin users.

For Class-Based Views:

from rest_framework.permissions import  IsAdminUser

class MyView(..):

    permisssion_classes = (IsAdminUser,) # set the permission class

    .. 

For Function-Based Views:

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

This will deny permission to any user having user.is_staff value as False, otherwise, permission will be allowed.

like image 59
Rahul Gupta Avatar answered Sep 26 '22 14:09

Rahul Gupta


My approach to this problem maybe not 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)
like image 38
Slipstream Avatar answered Sep 24 '22 14:09

Slipstream


The APIRootView class, which defines the view for the root /api/ endpoint, has an undocumented private attribute _ignore_model_permissions which is set to True. This attribute is used to ensure that DjangoModelPermissions are not applied to the root view, since the DefaultRouter root view has no queryset attribute, which is necessary for DjangoModelPermissions to work.

In short, if you set the APIRootView permissions to be something that is valid (e.g. IsAuthenticated) it is safe to set _ignore_model_permissions to False, which will cause the permission class to apply 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)

Note that we are modifying self.APIRootView since DefaultRouter pulls APIRootView in as an attribute.

Beware that _ignore_model_permissions is a private, undocumented attribute and so there is no guarantee this will continue to work in the future.

like image 22
Sam Hooke Avatar answered Sep 22 '22 14:09

Sam Hooke