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:
I'm wondering if there's a "proper" way of going about this.
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.
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.
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.
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.
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.
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)
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With